package com.yeyks.commonReference.service.order.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yeyks.account.dal.domain.AccountInfo;
import com.yeyks.account.utils.AccountUtil;
import com.yeyks.cnbooking.Result.prebookingcheck.CbPreBookingCheckData;
import com.yeyks.cnbooking.base.CNResponse;
import com.yeyks.cnbooking.base.prebookingcheck.CbPriceAndStatu;
import com.yeyks.cnbooking.param.CbPreBookingCheckParam;
import com.yeyks.cnbooking.service.CNBookingService;
import com.yeyks.common.appcommon.dto.account.AppIndexDTO;
import com.yeyks.common.appcommon.dto.finance.AppHotelBillDTO;
import com.yeyks.common.appcommon.dto.order.AppOrderInfoDTO;
import com.yeyks.common.appcommon.dto.order.AppOrderStatusDTO;
import com.yeyks.common.appcommon.json.JsonImageRoom;
import com.yeyks.common.appcommon.json.JsonOrderExtraInfo;
import com.yeyks.common.appcommon.json.JsonPersonInfo;
import com.yeyks.common.appcommon.param.QueryStatFeeParam;
import com.yeyks.common.appcommon.param.finance.QueryHotelBillParam;
import com.yeyks.common.appcommon.param.order.GetOrderDetailParam;
import com.yeyks.common.appcommon.param.order.GetOrderNoticeParam;
import com.yeyks.common.appcommon.param.order.QueryOrderParam;
import com.yeyks.common.appcommon.param.order.UpdateCheckInParam;
import com.yeyks.common.appcommon.result.CommonPage;
import com.yeyks.common.appcommon.result.CommonResult;
import com.yeyks.common.base.Arguments;
import com.yeyks.common.base.PageResult;
import com.yeyks.common.constants.*;
import com.yeyks.common.constants.cnbooking.CnBookingStaticConstant;
import com.yeyks.common.constants.hotel.HotelSourceType;
import com.yeyks.common.dto.HotelStatementResultDTO;
import com.yeyks.common.dto.mq.EsUpdateMessage;
import com.yeyks.common.dto.mq.OrderCheckToWebMessage;
import com.yeyks.common.em.FishBallEnum;
import com.yeyks.common.em.OrderStatusEnum;
import com.yeyks.common.em.RefundTypeEnum;
import com.yeyks.common.em.UserCouponInfoStatus;
import com.yeyks.common.em.order.OrderVipFlagEnum;
import com.yeyks.common.em.pay.PayTypeEnum;
import com.yeyks.common.em.vip.VipCardTypeEnum;
import com.yeyks.common.exception.ServiceException;
import com.yeyks.common.param.*;
import com.yeyks.common.param.finance.WithdrawalPeriodOrderParam;
import com.yeyks.common.param.screen.DataScreenOrderParam;
import com.yeyks.common.result.*;
import com.yeyks.common.result.order.UserOrderResult;
import com.yeyks.common.result.screen.DataScreenCityOrderResult;
import com.yeyks.common.result.screen.DataScreenOrderMonthResult;
import com.yeyks.common.result.screen.DataScreenOrderResult;
import com.yeyks.common.result.screen.DataScreenSyncNameResult;
import com.yeyks.common.utils.*;
import com.yeyks.common.utils.apputil.bean.MyBeanUtils;
import com.yeyks.commonReference.append.alipay.service.AlipayService;
import com.yeyks.commonReference.append.rocketmq.service.producer.MQProducerService;
import com.yeyks.commonReference.append.sms.SmsService;
import com.yeyks.commonReference.append.wxPay.dto.WxRefundParam;
import com.yeyks.commonReference.append.wxPay.service.WeiXinPayService;
import com.yeyks.commonReference.pojo.param.OrderInfoC2bPlaceAnOrderParam;
import com.yeyks.commonReference.pojo.vo.OrderHeadOrderDetailsVo;
import com.yeyks.commonReference.service.account.AccountInfoService;
import com.yeyks.commonReference.service.calendar.RoomCalendarJipInfoService;
import com.yeyks.commonReference.service.config.ConfigService;
import com.yeyks.commonReference.service.consumer.MemberCardService;
import com.yeyks.commonReference.service.consumer.MessageNoticeTemplateService;
import com.yeyks.commonReference.service.consumer.UserCouponInfoService;
import com.yeyks.commonReference.service.consumer.UserMemberCardService;
import com.yeyks.commonReference.service.hotel.HotelDeveloperRelationService;
import com.yeyks.commonReference.service.hotel.HotelInfoService;
import com.yeyks.commonReference.service.hotel.RoomInfoService;
import com.yeyks.commonReference.service.message.MessageService;
import com.yeyks.commonReference.service.order.OrderBillService;
import com.yeyks.commonReference.service.order.OrderHeadService;
import com.yeyks.commonReference.service.order.OrderPickRecordService;
import com.yeyks.commonReference.service.other.CouponInfoService;
import com.yeyks.commonReference.service.vip.AccountVipSalerRelationService;
import com.yeyks.commonReference.service.vip.MiniVipCommissionBillService;
import com.yeyks.config.pojo.param.WebConfigurationSystemVersionParam;
import com.yeyks.config.service.WebConfigurationService;
import com.yeyks.consumer.dal.domain.MemberCard;
import com.yeyks.consumer.dal.domain.UserCouponInfo;
import com.yeyks.consumer.dal.domain.UserInfo;
import com.yeyks.consumer.dal.domain.UserMemberCard;
import com.yeyks.consumer.service.FishBallService;
import com.yeyks.consumer.service.MessageNoticeService;
import com.yeyks.consumer.service.UserInfoService;
import com.yeyks.hotel.dal.domain.*;
import com.yeyks.hotel.dto.PayAccountDTO;
import com.yeyks.hotel.param.HotelExtraInfo;
import com.yeyks.hotel.service.RoomCalendarInfoService;
import com.yeyks.hotel.service.RoomCalendarVipInfoService;
import com.yeyks.hotel.utils.HotelSearchUtil;
import com.yeyks.order.dal.dao.OrderHeadMapper;
import com.yeyks.order.dal.domain.OrderBill;
import com.yeyks.order.dal.domain.OrderHead;
import com.yeyks.order.dal.domain.OrderPickRecord;
import com.yeyks.order.param.*;
import com.yeyks.order.vo.OrderHeadC2bPlaceAnOrderVo;
import com.yeyks.order.vo.OrderHeadFindNoPayOrderVo;
import com.yeyks.order.vo.OrderHeadOrderListVo;
import com.yeyks.order.vo.OrderHeadRefundAmountVo;
import com.yeyks.other.dal.domain.AddressCode;
import com.yeyks.other.dal.domain.CouponInfo;
import com.yeyks.other.service.AddressCodeService;
import com.yeyks.search.constants.EsIndexConstant;
import com.yeyks.search.pojo.model.EsHotelInfo;
import com.yeyks.search.pojo.model.EsRoomCalendarInfo;
import com.yeyks.search.pojo.model.EsRoomInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.join.query.JoinQueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.yeyks.common.utils.apputil.type.QueryDateType.ONE_MONTH;


/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author yun
 * @since 2019-06-25
 */
@Service
@Slf4j
public class OrderHeadServiceImpl extends ServiceImpl<OrderHeadMapper, OrderHead> implements OrderHeadService {

    private List<Integer> orderTypeListBefore = CollectionUtil.newArrayList(1, 2, 3);
    private List<Integer> orderTypeListNow = CollectionUtil.newArrayList(10);

    @Autowired
    private RestHighLevelClient restHighLevelClient;
    @Autowired
    private CNBookingService cnBookingService;
    @Autowired
    private RoomInfoService RoomInfoService;
    @Autowired
    private HotelInfoService hotelInfoService;
    @Autowired
    private RoomCalendarInfoService roomCalendarInfoService;
    @Autowired
    private RoomCalendarVipInfoService roomCalendarVipInfoService;
    @Autowired
    private RoomCalendarJipInfoService roomCalendarJipInfoService;
    @Autowired
    private CouponInfoService couponInfoService;
    @Autowired
    private UserCouponInfoService userCouponInfoService;
    @Autowired
    private OrderBillService orderBillService;
    @Autowired
    private UserMemberCardService userMemberCardService;
    @Autowired
    private AlipayService alipayService;
    @Autowired
    private WeiXinPayService wxLoginService;
    @Autowired
    private MessageService messageService;
    @Autowired
    private UserCouponInfoService userCouponService;
    @Autowired
    private SmsService smsService;
    @Autowired
    private MessageNoticeService noticeService;
    @Autowired
    private MessageNoticeTemplateService templateService;
    @Autowired
    private MemberCardService memberCardService;
    @Autowired
    private RoomInfoService roomInfoService;
    @Autowired
    private FishBallService fishBallService;
    @Autowired
    private ConfigService configService;
    @Autowired
    private OrderPickRecordService orderPickRecordService;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private MQProducerService mqProducerService;
    @Autowired
    private AccountVipSalerRelationService accountVipSalerRelationService;
    @Autowired
    private HotelDeveloperRelationService hotelDeveloperRelationService;
    @Autowired
    private AccountInfoService accountInfoService;
    @Autowired
    private AddressCodeService addressCodeService;
    @Autowired
    private MiniVipCommissionBillService miniVipCommissionBillService;
    @Autowired
    private WebConfigurationService webConfigurationService;

    @Override
    public OrderHead getByOrderNo(String orderNo) {
        return getOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, orderNo));
    }

    /**
     * 根据第三方订单号获取订单
     *
     * @param sourceOrderId 订单号
     * @return
     */
    @Override
    public OrderHead getBySourceOrderId(String sourceOrderId) {
        return getOne(new QueryWrapper<OrderHead>().eq(OrderHead.SOURCE_ORDER_ID, sourceOrderId).last("limit 1"));

    }

    @Override
    public PageInfo<OrderHeadOrderListVo> orderList(OrderHeadOrderListParam param) {
        switch (param.getType()) {
            //已付款
            case 2:
                param.setStatusList(CollectionUtil.list(false
                        , OrderStatus.preCheckIn
                        , OrderStatus.postCheckOut
                        , OrderStatus.preRefund
                        , OrderStatus.living
                        , OrderStatus.postCheckOut
                        , OrderStatus.comment));
                break;
            //未支付
            case 3:
                param.setStatusList(CollectionUtil.list(false
                        , OrderStatus.prePay));
                break;
            //已取消
            case 4:
                param.setStatusList(CollectionUtil.list(false
                        , OrderStatus.payFailed
                        , OrderStatus.postRefund
                        , OrderStatus.cancle));
                break;
            //全部
            case 1:
            default:
                break;
        }
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<OrderHeadOrderListVo> orderHeadOrderListVos = baseMapper.orderList(param);
        PageInfo<OrderHeadOrderListVo> orderHeadOrderListVoPageInfo = new PageInfo<>(orderHeadOrderListVos);
        return orderHeadOrderListVoPageInfo;
    }

    @Override
    public OrderHeadOrderDetailsVo orderDetails(OrderHeadOrderDetailsParam param) {
        OrderHead orderHead = getOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, param.getOrderNo())
                .eq(OrderHead.USER_ID, param.getUserId()).eq(OrderHead.DELETE_FLAG, DeleteFlag.NO));
        if (null == orderHead) {
            throw new ServiceException("订单不存在");
        }
        List<OrderBill> orderBillList = orderBillService.list(new QueryWrapper<OrderBill>().eq(OrderBill.ORDER_NO, param.getOrderNo()));
        OrderHeadOrderDetailsVo orderHeadOrderDetailsVo = new OrderHeadOrderDetailsVo();
        orderHeadOrderDetailsVo.setOrderHead(orderHead).setOrderBills(orderBillList);
        return orderHeadOrderDetailsVo;
    }

    //退款
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean cancelOrder(OrderHeadCancelOrderParam param) {
        //查询
        OrderHead orderHead = getOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, param.getOrderNo())
                .eq(OrderHead.USER_ID, param.getUserId()).eq(OrderHead.DELETE_FLAG, DeleteFlag.NO));
        if (null == orderHead) {
            throw new ServiceException("订单不存在或无法执行该操作");
        }
        //第三方订单不支持取消
        if (StrUtil.isNotBlank(orderHead.getSourceType()) && !Objects.equals(orderHead.getSourceType(), HotelSourceType.YYKS)) {
            throw new ServiceException("该订单不支持取消操作");
        }
        //判断状态
        if (!CollectionUtil.list(false, OrderStatus.prePay, OrderStatus.preCheckIn).contains(orderHead.getStatus())) {
            throw new ServiceException("该订单状态不能进行该操作");
        }
        //判断是否是入住那天的6点之前
        DateTime ableRefundTime = DateUtil.offsetHour(DateUtil.beginOfDay(orderHead.getCheckIn()), 18);
        if (new Date().after(ableRefundTime)) {
            if(CollectionUtil.list(false, OrderStatus.preCheckIn).contains(orderHead.getStatus())){
                throw new ServiceException("该订单超过可退款期限不能进行该操作");
            }
        }
        //取消第三方订单
//        if (StrUtil.isNotBlank(orderHead.getSourceType())) {
//            switch (orderHead.getSourceType()) {
//                case HotelSourceType.CN:
//                    CbOrderCancelParam cbOrderCancelParam = new CbOrderCancelParam();
//                    cbOrderCancelParam.setOrderId(orderHead.getSourceOrderId());
//                    CNResponse<CbBookingCancelData> cbBookingCancelDataCNResponse = cnBookingService.bookingCancel(cbOrderCancelParam);
//                    if (!Objects.equals(cbBookingCancelDataCNResponse.getMessageInfo().getCode(), CnBookingStaticConstant.CODE_SUCCESS)) {
//                        String returnCode = cbBookingCancelDataCNResponse.getData().getReturnCode();
//                        if (Objects.equals(returnCode, CnBookingStaticConstant.CODE_BOOKING_CANCEL_SUCCESS)) {
//                        } else if (Objects.equals(returnCode, CnBookingStaticConstant.CODE_BOOKING_ALREADY_CANCEL_SUCCESS)) {
//                            TryCatchUtil.tryCatch(() -> log.error("第三方订单已取消:{}", orderHead.getOrderNo()));
//                        } else {
//                            throw new ServiceException("取消订单失败");
//                        }
//                    }
//                    break;
//            }
//        }
        //退款
        cancelOrderNoCheck(orderHead.getOrderNo(), param.getRefundReason());
        //        TryCatchUtil.tryCatch(() -> {
//            mqProducerService.sendRefundNoticeMsg(new RefundNoticeMessage().setOrderNo(param.getOrderNo()));
//        });
        return true;
    }

    //退款inner
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrderNoCheck(String orderNo, String refundReason) {
        OrderHead orderHead = getOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, orderNo).eq(OrderHead.DELETE_FLAG, DeleteFlag.NO));
        if (null == orderHead) {
            throw new ServiceException("订单不存在或无法执行该操作");
        }
        //判断状态
        if (CollectionUtil.list(false, OrderStatus.preCheckIn).contains(orderHead.getStatus())) {
            //退款
            boolean b = refund(orderHead.getOrderNo(), orderHead.getSnapshotTotalFee());
            if (!b) {
                throw new ServiceException("退款失败");
            }
            //修改订单状态
            OrderHead orderHeadNew = new OrderHead()
                    .setId(orderHead.getId())
                    .setStatus(OrderStatus.postRefund)
                    .setSnapshotRefundFee(getRefundAmount(orderHead))
                    .setRefundReason(refundReason);
            b = updateById(orderHeadNew);
            if (!b) {
                TryCatchUtil.tryCatch(() -> log.error("取消订单的订单状态修改失败:{}", JSONUtil.toJsonStr(orderHead)));
            }
        }else {
            //修改订单状态
            OrderHead orderHeadNew = new OrderHead()
                    .setId(orderHead.getId())
                    .setStatus(OrderStatus.cancle)
                    .setSnapshotRefundFee(getRefundAmount(orderHead))
                    .setRefundReason(refundReason);
            boolean b = updateById(orderHeadNew);
            if (!b) {
                TryCatchUtil.tryCatch(() -> log.error("取消订单的订单状态修改失败:{}", JSONUtil.toJsonStr(orderHead)));
            }
        }
    }

    /**
     * 封装公共方法,需提前做判断
     * 根据订单号和退款金额进行退款
     *
     * @param orderNo      订单号
     * @param refundAmount 退款金额
     * @return
     */
    private boolean refund(String orderNo, Integer refundAmount) {
        OrderHead orderHead = getOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, orderNo));
        boolean updateFlag = false;
        //支付宝退款(元)
        if (PayTypeEnum.ALIPAY.value().equals(orderHead.getPaymentMethod())) {
            Boolean flag = alipayService.tradeRefund(orderNo, refundAmount);
            if (flag) {
                updateCouponAndRoomCount(orderHead);
                updateFlag = true;
            } else {
                throw new ServiceException("支付宝退款失败");
            }
        }
        //微信相关退款（分）
        if (PayTypeEnum.WXPAY.value().equals(orderHead.getPaymentMethod())
                || PayTypeEnum.GZH.value().equals(orderHead.getPaymentMethod())
                || PayTypeEnum.XCX.value().equals(orderHead.getPaymentMethod())) {
            if (PayTypeEnum.XCX.value().equals(orderHead.getPaymentMethod())) {
                orderNo += "xcx";
            }
            WxRefundParam wxpay = new WxRefundParam(PayTypeEnum.getDesc(orderHead.getPaymentMethod()), orderNo, orderNo + 888, orderHead.getSnapshotTotalFee(), refundAmount);
            Boolean flag = wxLoginService.disPoseRefund(wxpay);
            if (flag) {
                updateCouponAndRoomCount(orderHead);
                updateFlag = true;
            } else {
                throw new ServiceException("微信退款失败");
            }
        }
        //钱包退款（分）
        if (PayTypeEnum.WALLET.value().equals(orderHead.getPaymentMethod())) {
            try {
                memberCardService.refundAmountV2(orderHead, refundAmount);
                updateCouponAndRoomCount(orderHead);
                updateFlag = true;
            } catch (ServiceException e) {
                throw new ServiceException(e.getMessage());
            } catch (Exception e) {
                log.info("钱包退款失败{}", e.getLocalizedMessage());
                e.printStackTrace();
                throw new ServiceException("钱包退款失败");
            }
        }
        return updateFlag;
    }

    //获取退款金额
    @Override
    public OrderHeadRefundAmountVo refundAmount(OrderHeadRefundAmountParam param) {
        //查询
        OrderHead orderHead = getOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, param.getOrderNo())
                .eq(OrderHead.USER_ID, param.getUserId()).eq(OrderHead.DELETE_FLAG, DeleteFlag.NO));
        OrderHeadRefundAmountVo vo = new OrderHeadRefundAmountVo();
        vo.setRefundAmount(getRefundAmount(orderHead));
        vo.setTotalFee(orderHead.getSnapshotTotalFee());
        return vo;
    }

    //获取退款金额
    private Integer getRefundAmount(OrderHead orderHead) {
        Integer snapshotTotalFee = orderHead.getSnapshotTotalFee();
        //18点之后将退款金额改为0
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(orderHead.getCheckIn());
        calendar.set(Calendar.HOUR_OF_DAY, 18);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        if (new Date().after(calendar.getTime())) {
            snapshotTotalFee = 0;
        }
        return snapshotTotalFee;
    }

    @Override
    public Boolean delOrder(OrderHeadDelOrderParam param) {
        //查询
        OrderHead orderHead = getOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, param.getOrderNo())
                .eq(OrderHead.USER_ID, param.getUserId()).eq(OrderHead.DELETE_FLAG, DeleteFlag.NO));
        if (null == orderHead) {
            throw new ServiceException("订单不存在或无法执行该操作");
        }
        //判断状态
        if (!CollectionUtil.list(false
                , OrderStatus.postCheckOut
                , OrderStatus.postRefund
                , OrderStatus.cancle
                , OrderStatus.comment)
                .contains(orderHead.getStatus())) {
            throw new ServiceException("该订单状态不能进行此次操作");
        }
        //修改
        OrderHead orderHeadNew = new OrderHead().setId(orderHead.getId()).setDeleteFlag(1);
        boolean b = updateById(orderHeadNew);
        return b;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean evaluateOrder(OrderHeadEvaluateOrderParam param) {
        QueryWrapper<OrderHead> queryWrapper = new QueryWrapper<OrderHead>()
                .eq(OrderHead.USER_ID, param.getUserId())
                .eq(OrderHead.ORDER_NO, param.getOrderNo())
                .eq(OrderHead.STATUS, OrderStatus.postCheckOut);
        OrderHead orderHead = getOne(queryWrapper);
        if (null == orderHead) {
            throw new ServiceException("订单不存在或者状态不正确");
        }
        boolean b = update(new OrderHead().setScore(param.getScore()).setStatus(OrderStatus.comment), queryWrapper);
        if (!b) {
            throw new ServiceException("订单评分失败");
        }
        if (Objects.equals(orderHead.getSourceType(), HotelSourceType.YYKS)) {
            Integer integer = hotelInfoService.updateScore(orderHead.getHotelId());
            if (integer < 1) {
                throw new ServiceException("订单评分失败");
            }
        }
        //评论成功返鱼宝
        fishBallService.addFishBall(FormatUtils.fen2YuanInt(orderHead.getSnapshotTotalFee()), orderHead.getUserId(), 1, FishBallEnum.COMMIT.desc());
        return b;
    }

    @Override
    public Boolean checkOrderUserCouponInfoCount(Integer userId) {
        return checkOrderUserCouponInfoCount(userId, getCouponEnablePerDay());
    }

    //获取一天可以使用的优惠券数量
    public Integer getCouponEnablePerDay() {
        String value = configService.getValue(ConfigKey.COUPON_CAN_USE_PER_DAY);
        try {
            return Integer.valueOf(value);
        } catch (Exception e) {
            e.printStackTrace();
            return 1;
        }
    }

    //判断该酒店是否能用大礼包券
//    @Override
//    public Boolean checkHotelCanBeUseCouponInfoType8(Integer hotelId) {
//        HotelInfo hotelInfo = hotelInfoService.getOne(
//                new QueryWrapper<HotelInfo>()
//                        .eq(HotelInfo.ID, hotelId)
//                        .last("limit 1")
//        );
//        if (Objects.isNull(hotelInfo)) {
//            throw new ServiceException("酒店不存在");
//        }
//        return Objects.equals(hotelInfo.getVipFlag(), OrderVipFlagEnum.JIP.getValue());
//    }

    //判断该酒店是否能用该券
//    public Boolean checkOrderUserCouponInfoHotelCanBeUse(Integer userId, Integer hotelId, Integer userCouponInfoId) {
//        HotelInfo hotelInfo = hotelInfoService.getOne(
//                new QueryWrapper<HotelInfo>()
//                        .eq(HotelInfo.ID, hotelId)
//                        .last("limit 1")
//        );
//        if (Objects.isNull(hotelInfo)) {
//            throw new ServiceException("酒店不存在");
//        }
//        UserCouponInfo userCouponInfo = userCouponInfoService.getOne(
//                new QueryWrapper<UserCouponInfo>()
//                        .eq(UserCouponInfo.ID, userCouponInfoId)
//                        .eq(UserCouponInfo.USER_ID, userId)
//                        .last("limit 1")
//        );
//        if (Objects.isNull(userCouponInfo)) {
//            throw new ServiceException("优惠券不存在");
//        }
//        CouponInfo couponInfo = couponInfoService.getOne(
//                new QueryWrapper<CouponInfo>()
//                        .eq(CouponInfo.ID, userCouponInfo.getCouponId())
//                        .last("limit 1")
//        );
//        if (Objects.equals(couponInfo.getType(), CouponConst.bagGift) && !checkHotelCanBeUseCouponInfoType8(hotelId)) {
//            return false;
//        }
//        return true;
//    }

    //基于数量判断是否可用优惠券
    public Boolean checkOrderUserCouponInfoCount(Integer userId, Integer num) {
        DateTime todayBegin = DateUtil.beginOfDay(new Date());
        DateTime tomorrowBegin = DateUtil.offsetDay(todayBegin, 1);
        int count = count(new QueryWrapper<OrderHead>()
                .eq(OrderHead.USER_ID, userId)
                .ge(OrderHead.GMT_CREATE, todayBegin)
                .lt(OrderHead.GMT_CREATE, tomorrowBegin)
                .in(OrderHead.STATUS
                        , OrderStatus.prePay
                        , OrderStatus.preCheckIn
                        , OrderStatus.postCheckOut
                        , OrderStatus.preRefund
                        , OrderStatus.living
                        , OrderStatus.comment
                )
                .isNotNull(OrderHead.USER_COUPON_ID)
        );
        if (count >= num) {
            return false;
        } else {
            return true;
        }
    }

    //下单
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderHeadC2bPlaceAnOrderVo c2bPlaceAnOrder(OrderInfoC2bPlaceAnOrderParam param) {

        if(param.getVipFlag() == 3){
            //todo 判断日期是否合格
            WebConfigurationSystemVersionParam webParam = new WebConfigurationSystemVersionParam();
            webParam.setVersion(1);
            webParam.setKey("calendar.booking.delay.count");
            //往后推迟几天
            String overDay = webConfigurationService.getValue(webParam);
            if(!"0".equals(overDay)){
                DateTime minStartTime = DateUtil.offsetDay(DateUtil.date(), Integer.parseInt(overDay));
                DateTime dateTime = DateUtil.beginOfDay(minStartTime);
                //比较时间
                if(DateUtil.compare(dateTime, param.getStartDate()) > 0){
                    throw new ServiceException("当前入住时间没有开放，请重新选择！");
                }
            }
        }
        if (orderTypeListNow.contains(param.getVipFlag())) {
            return c2bPlaceAnOrderNow(param);
        } else {
            return c2bPlaceAnOrderBefore(param);
        }
    }

    //v3.6 下单
    public OrderHeadC2bPlaceAnOrderVo c2bPlaceAnOrderNow(OrderInfoC2bPlaceAnOrderParam param) {
        try {
            //判断订单类型
            if (!orderTypeListNow.contains(param.getVipFlag())) {
                throw new ServiceException("订单类型错误");
            }
            //修正时间
            param.setStartDate(DateUtil.beginOfDay(param.getStartDate()).toJdkDate());
            param.setEndDate(DateUtil.beginOfDay(param.getEndDate()).toJdkDate());
//            //时间修正
//            param.setStartDate(HotelSearchUtil.fixDate(param.getStartDate()));
//            param.setEndDate(HotelSearchUtil.fixDate(param.getEndDate()));
            //时间校验
            HotelSearchUtil.checkSearchDate(param.getStartDate(), param.getEndDate());


            //参数校验
            Long days = DateUtil.between(param.getStartDate(), param.getEndDate(), DateUnit.DAY);
            OrderPickRecord orderPickRecord = null;
            switch (param.getVipFlag()) {
                case 10:
                    //校验是否有timestamp
                    if (Objects.isNull(param.getTimestamp())) {
                        throw new ServiceException("非抢单订单,请重试");
                    }
                    long timeDifference = System.currentTimeMillis() - param.getTimestamp();
                    //校验时间戳
                    //校验下单时间是否超时
                    if (timeDifference > (8 * 60 * 1000)) {
                        throw new ServiceException("超过允许下单的时间");
                    }
                    //校验抢单记录
                    orderPickRecord = orderPickRecordService.getOne(
                            new QueryWrapper<OrderPickRecord>()
                                    .eq(OrderPickRecord.USER_ID, param.getUserId())
                                    .eq(OrderPickRecord.TIMESTAMP, param.getTimestamp())
                                    .eq(OrderPickRecord.SOURCE_TYPE, param.getSourceType())
                                    .eq(OrderPickRecord.SOURCE_ROOM_ID, param.getSourceRoomId())
                                    .last("limit 1")
                    );
                    if (Objects.isNull(orderPickRecord)) {
                        throw new ServiceException("抢单记录不存在");
                    }
                    break;
            }


            //房间 酒店 房态信息
            //
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                    //房间
                    .must(
                            QueryBuilders.boolQuery()
                                    .must(
                                            QueryBuilders.termQuery("sourceType", param.getSourceType())
                                    )
                                    .must(
                                            QueryBuilders.termQuery("sourceId", param.getSourceRoomId())
                                    )
                    )
                    //酒店
                    .must(
                            JoinQueryBuilders.hasParentQuery(
                                    EsIndexConstant.JOIN_TYPE_HOTEL,
                                    QueryBuilders.matchAllQuery(),
                                    false
                            ).innerHit(new InnerHitBuilder().setSize(100))
                    )
                    //房态
                    .must(
                            JoinQueryBuilders.hasChildQuery(
                                    EsIndexConstant.JOIN_TYPE_CALENDAR,
                                    QueryBuilders.rangeQuery("date")
                                            .gte(param.getStartDate())
                                            .lt(param.getEndDate())
                                    ,
                                    ScoreMode.None
                            ).innerHit(new InnerHitBuilder().setSize(100))
                    );
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.size(10);
            searchSourceBuilder.query(boolQueryBuilder);
            //
            SearchRequest searchRequest = new SearchRequest(EsIndexConstant.INDEX_HOTEL);
            searchRequest.types(EsIndexConstant.NORMAL_TYPE);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            //转换数据
            //房间
            if (searchResponse.getHits().getTotalHits() != 1) {
                throw new ServiceException("房间信息不存在");
            }
            SearchHit searchHitRoom = searchResponse.getHits().getHits()[0];
            EsRoomInfo esRoomInfo = JSONUtil.toBean(searchHitRoom.getSourceAsString(), EsRoomInfo.class);
            //酒店
            if (searchHitRoom.getInnerHits().get(EsIndexConstant.JOIN_TYPE_HOTEL).getTotalHits() != 1) {
                throw new ServiceException("酒店信息不存在");
            }
            EsHotelInfo esHotelInfo = JSONUtil.toBean(searchHitRoom.getInnerHits().get(EsIndexConstant.JOIN_TYPE_HOTEL).getHits()[0].getSourceAsString(), EsHotelInfo.class);
            //房态
            if (searchHitRoom.getInnerHits().get(EsIndexConstant.JOIN_TYPE_CALENDAR).getTotalHits() < 1) {
                throw new ServiceException("房态信息不存在");
            }
            SearchHit[] searchHitCalendars = searchHitRoom.getInnerHits().get(EsIndexConstant.JOIN_TYPE_CALENDAR).getHits();
            ArrayList<EsRoomCalendarInfo> esRoomCalendarInfos = new ArrayList<>();
            for (SearchHit searchHitCalendar : searchHitCalendars) {
                esRoomCalendarInfos.add(JSONUtil.toBean(searchHitCalendar.getSourceAsString(), EsRoomCalendarInfo.class));
            }
            //校验
            //每日下单优惠券限制
            switch (param.getVipFlag()) {
                //c2b
                case 10:
                    if (Objects.nonNull(param.getUserCouponInfoId())) {
                        Integer couponEnablePerDay = getCouponEnablePerDay();
                        //一天只能使用一张优惠券
                        if (!checkOrderUserCouponInfoCount(param.getUserId(), couponEnablePerDay)) {
                            throw new ServiceException(String.format("每天只能使用%d张优惠券", couponEnablePerDay));
                        }
                    }
                    break;
            }
            //房间
            switch (param.getVipFlag()) {
                case 10:
                    if (Objects.equals(0, esRoomInfo.getValid())) {
                        throw new ServiceException("房间未上架");
                    }
                    break;
            }
            //酒店
            //房态
            switch (param.getVipFlag()) {
                //c2b
                case 10:
                    //检查房态数量
                    if (CompareUtil.compare(Long.valueOf(esRoomCalendarInfos.size()), days) != 0) {
                        throw new ServiceException("房间数量不足！");
                    }
                    //检查剩余房间数量
                    for (EsRoomCalendarInfo esRoomCalendarInfo : esRoomCalendarInfos) {
                        if (Objects.equals(0, esRoomCalendarInfo.getStatus())) {
                            throw new ServiceException("房间数量不足");
                        }
                        if (esRoomCalendarInfo.getCount() < param.getRoomCount()) {
                            throw new ServiceException("房间数量不足");
                        }
                    }
                    break;
            }


            //订单号
            String orderNo = IdWorkerUtil.nextStrId();
            //添加类别
            switch (param.getVipFlag()) {
                //c2b
                case 0:
                case 10:
                    orderNo = "c2b" + orderNo;
                    break;
                //vip
                case 1:
                    orderNo = "vip" + orderNo;
                    break;
                //jip
                case 3:
                    orderNo = "jip" + orderNo;
                    break;
                //v3.4 b2c
                case 2:
                    orderNo = "b2c" + orderNo;
                    break;
            }
            //添加来源
            if (StrUtil.isBlank(param.getSourceType())) {
                orderNo = HotelSourceType.YYKS + orderNo;
            } else {
                orderNo = param.getSourceType() + orderNo;
            }
            //最终付款全价
            Integer snapshotOriginTotalFee = 0;
            switch (param.getVipFlag()) {
                //c2b抢单
                case 10:
                    snapshotOriginTotalFee = orderPickRecord.getUserShowPrice() * days.intValue() * param.getRoomCount();
                    break;
            }


            //利润
            Integer vipProfit = null;


            //生成订单
            OrderHead orderHead = new OrderHead();
            Date createTime = new Date();
            orderHead.setGmtCreate(createTime);
            orderHead.setGmtModified(createTime);
            orderHead.setOrderNo(orderNo);
            orderHead.setUserId(param.getUserId());
            if (Objects.equals(param.getSourceType(), HotelSourceType.YYKS)) {
                orderHead.setRoomId(param.getRoomId());
                orderHead.setHotelId(esHotelInfo.getId());
            }
            orderHead.setSnapshotHotelName(esHotelInfo.getName());
            orderHead.setSnapshotRoomName(esRoomInfo.getTitle());
            orderHead.setSnapshotOriginTotalFee(snapshotOriginTotalFee);
            orderHead.setStatus(1);
            orderHead.setCheckIn(param.getStartDate());
            orderHead.setCheckOut(param.getEndDate());
            orderHead.setDays(days.intValue());
            orderHead.setRoomCount(param.getRoomCount());
            orderHead.setContactName(param.getConsumerName());
            orderHead.setContactPhone(param.getConsumerPhone());
            orderHead.setVipProfit(vipProfit);
            orderHead.setDeleteFlag(0);
            orderHead.setProvinceAgentId(esHotelInfo.getProvinceAgentId());
            orderHead.setCityAgentId(esHotelInfo.getCityAgentId());
            orderHead.setAreaAgentId(esHotelInfo.getAdminId());
            orderHead.setVipFlag(param.getVipFlag());
            //3.4的抢单订单类型和3.3的c2b一样
            if (Objects.equals(param.getVipFlag(), 10)) {
                orderHead.setVipFlag(0);
            }
            orderHead.setFeeValue(0);
            orderHead.setLeaveMessage(param.getLeaveMessage());
            if (Objects.nonNull(esHotelInfo.getParentTax())) {
                orderHead.setYeyuRate(esHotelInfo.getParentTax() * 10);
            }
            String hotelExt = esHotelInfo.getExtraInfo();
            String roomExt = esHotelInfo.getExtraInfo();
            //填充附加信息
            HashMap<String, Object> map = new HashMap<>();
            TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.HOTEL_ADDRESS, esHotelInfo.getAddress()));
            TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.HOTEL_PHONE, esHotelInfo.getPhone()));
            TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.HOTEL_TEL, esHotelInfo.getTel()));
            TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.HOTEL_IMG_URLS, JSONUtil.parseObj(hotelExt).getJSONArray("imgUrlList").toList(String.class)));
            TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.ROOM_IMG_URLS, JSONUtil.parseObj(roomExt).getJSONArray("imgUrlList").toList(String.class)));
            if (Objects.equals(param.getVipFlag(), 10)) {
                TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.GRAB_THE_ORDER_TIMESTAMP, param.getTimestamp()));
            }
            orderHead.setExtraInfo(JSONUtil.toJsonStr(map));


            //最终付款优惠价
            Integer snapshotTotalFee = snapshotOriginTotalFee;
            //优惠券信息
            switch (param.getVipFlag()) {
                //c2b抢单
                case 10:
                    if (null != param.getUserCouponInfoId()) {
                        if (Objects.equals(0, esHotelInfo.getEnabledCoupon())) {
                            throw new ServiceException("该酒店不能使用优惠券");
                        }
                        UserCouponInfo userCouponInfo = userCouponInfoService.getOne(new QueryWrapper<UserCouponInfo>()
                                .eq(UserCouponInfo.ID, param.getUserCouponInfoId()).eq(UserCouponInfo.USER_ID, param.getUserId())
                                .eq(UserCouponInfo.USED, 0));
                        if (null == userCouponInfo) {
                            throw new ServiceException("优惠券不存在");
                        }
                        if (0 != userCouponInfo.getUsed()) {
                            throw new ServiceException("优惠券非未使用状态");
                        }
                        if (userCouponInfo.getOverTime().before(new Date())) {
                            throw new ServiceException("优惠券已经过期");
                        }
                        orderHead.setUserCouponId(userCouponInfo.getId());
                        CouponInfo couponInfo = couponInfoService.getById(userCouponInfo.getCouponId());
                        if (snapshotOriginTotalFee < couponInfo.getValidFee()) {
                            throw new ServiceException("优惠券未达到使用条件");
                        }
                        //设置优惠后的金额
                        snapshotTotalFee -= userCouponInfo.getCouponValue();
                        if (snapshotTotalFee < 1) {
                            snapshotTotalFee = 1;
                        }
                        //锁定优惠券
                        UserCouponInfo userCouponInfoNew = new UserCouponInfo()
                                .setId(userCouponInfo.getId()).setUsed(UserCouponInfoStatus.LOCK.value());
                        boolean b = userCouponInfoService.updateById(userCouponInfoNew);
                        if (!b) {
                            throw new ServiceException("优惠券更新失败");
                        }
                    }
                    break;
            }
            orderHead.setSnapshotTotalFee(snapshotTotalFee);


            //联合订单参数
            orderHead.setSourceType(param.getSourceType());
            orderHead.setSourceHotelId(esHotelInfo.getSourceId());
            orderHead.setSourceRoomId(esRoomInfo.getSourceId());
            //第三方订单价格
            Integer sourceAmount = 0;
            if (Objects.nonNull(param.getSourceType()) && !Objects.equals(param.getSourceType(), HotelSourceType.YYKS)) {
                //第三方订单价格
                switch (param.getVipFlag()) {
                    //c2b抢单
                    case 10:
                        for (EsRoomCalendarInfo esRoomCalendarInfo : esRoomCalendarInfos) {
                            sourceAmount += esRoomCalendarInfo.getOriginPrice() * param.getRoomCount();
                        }
                        break;
                }
                orderHead.setSourceAmount(sourceAmount);
            }


            //第三方下单前校验
            switch (param.getSourceType()) {
                case HotelSourceType.CN:
                    CbPreBookingCheckParam cbPreBookingCheckParam = new CbPreBookingCheckParam();
                    cbPreBookingCheckParam.setHotelId(esHotelInfo.getSourceId());
                    cbPreBookingCheckParam.setRoomId(esRoomInfo.getSourceId());
                    cbPreBookingCheckParam.setRateplanId(esRoomCalendarInfos.get(0).getRatePlanId());
                    cbPreBookingCheckParam.setCheckIn(DatePattern.NORM_DATE_FORMAT.format(param.getStartDate()));
                    cbPreBookingCheckParam.setCheckOut(DatePattern.NORM_DATE_FORMAT.format(param.getEndDate()));
                    cbPreBookingCheckParam.setRoomCount(String.valueOf(param.getRoomCount()));
                    cbPreBookingCheckParam.setCurrency(CnBookingStaticConstant.RMB);
                    cbPreBookingCheckParam.setOrderAmount(String.valueOf(sourceAmount / 100));
                    log.info("cn下单校验请求参数记录,-----{}", cbPreBookingCheckParam);
                    CNResponse<CbPreBookingCheckData> cbPreBookingCheckDataCNResponse = cnBookingService.preBookingCheck(cbPreBookingCheckParam);
                    log.info("cn下单校验返回记录,-----{}------{}", orderHead.getOrderNo(), JSONUtil.toJsonStr(cbPreBookingCheckDataCNResponse));
                    if (!Objects.equals(cbPreBookingCheckDataCNResponse.getMessageInfo().getCode(), CnBookingStaticConstant.CODE_SUCCESS)
                            || !Objects.equals(cbPreBookingCheckDataCNResponse.getData().getReturnCode(), CnBookingStaticConstant.CODE_SUCCESS_SCHEDULED_VERIFICATION_PASS)) {
                        throw new ServiceException("该客房已被抢单，请重新选择");
                    }
                    CbPriceAndStatu cbPriceAndStatu = cbPreBookingCheckDataCNResponse.getData().getPriceAndStatus().get(0).getPriceAndStatu().get(0);
                    orderHead.setLastCancelTime(DateUtil.parse(cbPriceAndStatu.getLastCancelTime(), "yyyy/MM/dd hh:mm:ss").toJdkDate());

                    orderHead.setRateplanId(esRoomCalendarInfos.get(0).getRatePlanId());
                    break;
            }


            //添加省市名称
            switch (esHotelInfo.getSourceType()) {
                case HotelSourceType.YYKS:
                    //省名称
                    TryCatchUtil.tryCatch(() -> {
                        AccountInfo accountInfo = accountInfoService.getOne(
                                new QueryWrapper<AccountInfo>()
                                        .eq(AccountInfo.ID, esHotelInfo.getProvinceAgentId())
                        );
                        if (Objects.nonNull(accountInfo)) {
                            orderHead.setProvinceName(accountInfo.getArea());
                        }
                    });
                    //市名称
                    TryCatchUtil.tryCatch(() -> {
                        AccountInfo accountInfo = accountInfoService.getOne(
                                new QueryWrapper<AccountInfo>()
                                        .eq(AccountInfo.ID, esHotelInfo.getCityAgentId())
                        );
                        if (Objects.nonNull(accountInfo)) {
                            String[] split = accountInfo.getArea().split("\\.");
                            orderHead.setCityName(split[1]);
                        }
                    });
                    break;
                case HotelSourceType.CN:
                    //省名称
                    TryCatchUtil.tryCatch(() -> {
                        AddressCode addressCode = addressCodeService.getOne(
                                new QueryWrapper<AddressCode>()
                                        .eq(AddressCode.PROVINCE_ID, esHotelInfo.getProvinceId())
                                        .last("limit 1")
                        );
                        if (Objects.nonNull(addressCode)) {
                            orderHead.setProvinceName(addressCode.getProvinceName());
                        }
                    });
                    //市名称
                    TryCatchUtil.tryCatch(() -> {
                        AddressCode addressCode = addressCodeService.getOne(
                                new QueryWrapper<AddressCode>()
                                        .eq(AddressCode.CITY_ID, esHotelInfo.getCityId())
                                        .last("limit 1")
                        );
                        if (Objects.nonNull(addressCode)) {
                            orderHead.setCityName(addressCode.getCityName());
                        }
                    });

                    break;
            }


            //添加订单
            int createOrder = baseMapper.insert(orderHead);
            if (createOrder < 1) {
                throw new ServiceException("添加订单失败");
            }


            //添加订单详情
            ArrayList<OrderBill> orderBills = new ArrayList<>();
            switch (param.getVipFlag()) {
                //c2b抢单
                case 10:
                    for (EsRoomCalendarInfo esRoomCalendarInfo : esRoomCalendarInfos) {
                        OrderBill orderBill = new OrderBill();
                        orderBill.setOrderNo(orderHead.getOrderNo());
                        orderBill.setInDate(esRoomCalendarInfo.getDate());
                        orderBill.setOriginPrice(esRoomCalendarInfo.getOriginPrice());
                        orderBill.setSalePrice(esRoomCalendarInfo.getSalePrice());
                        switch (param.getVipFlag()) {
                            //c2b
                            case 0:
                                orderBill.setDealPrice(param.getPrice());
                                break;
                            //v3.4 b2c
                            case 2:
                                orderBill.setDealPrice(esRoomCalendarInfo.getSalePrice());
                                break;
                            //v3.4 c2b抢单
                            case 10:
                                orderBill.setDealPrice(orderPickRecord.getUserShowPrice());
                                break;
                        }
                        orderBill.setBottomPrice(esRoomCalendarInfo.getBottomPrice());
                        orderBill.setRoomCount(param.getRoomCount());
                        orderBill.setHotelExtraInfo(JSONUtil.toJsonStr(esHotelInfo));
                        orderBill.setRoomExtraInfo(JSONUtil.toJsonStr(esRoomInfo));
                        orderBill.setRoomCalendarInfo(JSONUtil.toJsonStr(esRoomCalendarInfo));
                        orderBill.setGmtCreate(new Date());
                        orderBills.add(orderBill);
                    }
                    break;
            }
            boolean b = orderBillService.saveBatch(orderBills);
            if (!b) {
                throw new ServiceException("添加订单详情失败");
            }


            //更新房态
            switch (param.getSourceType()) {
                case HotelSourceType.YYKS:
                    switch (param.getVipFlag()) {
                        //c2b抢单
                        case 10:
                            updateRoomCalendarInfo(orderNo, 1);
                            break;
                    }
                    break;
            }


            //发送订单超时检查消息
            mqProducerService.sendOrderCheckToWebMessage(new OrderCheckToWebMessage().setOrderNo(orderNo));
            OrderHeadC2bPlaceAnOrderVo orderHeadc2bPlaceAnOrderVo = new OrderHeadC2bPlaceAnOrderVo();
            orderHeadc2bPlaceAnOrderVo.setOrderNo(orderNo);
            return orderHeadc2bPlaceAnOrderVo;


        } catch (Exception e) {
            if (e instanceof ServiceException) {
                throw (ServiceException) e;
            }
            SystemStrackUtil.logYyksExceptionStack(e);
            throw new ServiceException("联合订单创建失败");
        }
    }

    public OrderHeadC2bPlaceAnOrderVo c2bPlaceAnOrderBefore(OrderInfoC2bPlaceAnOrderParam param) {
        //判断订单类型
        if (!orderTypeListBefore.contains(param.getVipFlag())) {
            throw new ServiceException("订单类型错误");
        }
        //修正时间
        param.setStartDate(DateUtil.beginOfDay(param.getStartDate()));
        param.setEndDate(DateUtil.beginOfDay(param.getEndDate()));
//        //时间修正
//        param.setStartDate(HotelSearchUtil.fixDate(param.getStartDate()));
//        param.setEndDate(HotelSearchUtil.fixDate(param.getEndDate()));
        //时间校验
        HotelSearchUtil.checkSearchDate(param.getStartDate(), param.getEndDate());
        //参数校验
        Long days = DateUtil.between(param.getStartDate(), param.getEndDate(), DateUnit.DAY);
        OrderPickRecord orderPickRecord = null;
        List<OrderHead> orderHeadList;
        switch (param.getVipFlag()) {
            //c2b
            case 0:
                if (null == param.getPrice() || param.getPrice() < 0) {
                    throw new ServiceException("抢单价不能为空");
                }
                break;
            //vip
            case 1:
                //设置不使用优惠券
                param.setUserCouponInfoId(null);
                //用户是否是vip
                if (!userMemberCardService.checkUserVip(param.getUserId(), VipCardTypeEnum.VIP.getValue())) {
                    throw new ServiceException("非甄选用户不能使用甄选功能");
                }
                //vip只能定一间房间并且最多只能定三天
                if (days > 3) {
                    throw new ServiceException("房间天数超限");
                }
                param.setRoomCount(1);
                //vip酒店订单校验
                orderHeadList = list(new QueryWrapper<OrderHead>()
                        .eq(OrderHead.USER_ID, param.getUserId())
                        .eq(OrderHead.VIP_FLAG, OrderVipFlagEnum.VIP.getValue())
                        .in(OrderHead.STATUS
                                , OrderStatus.prePay
                                , OrderStatus.preCheckIn
                                , OrderStatus.living
                        )
                );
                if (null != orderHeadList && orderHeadList.size() > 0) {
                    throw new ServiceException("同一时间只能订一间房间");
                }
                break;
            //jip
            case 3:
                //用户是否是jip
                if (!userMemberCardService.checkUserVip(param.getUserId(), VipCardTypeEnum.JIP.getValue())) {
                    throw new ServiceException(403001,"非精选用户不能使用精选功能");
                }
                //设置不使用优惠券
                param.setUserCouponInfoId(null);
                UserInfo userInfo = userInfoService.getById(param.getUserId());
                if (!Objects.equals(userInfo.getType(), 2)) {
                    //jip只能定一间房间并且最多只能定三天
                    if (days > 3) {
                        throw new ServiceException("房间天数超限");
                    }
                    param.setRoomCount(1);
                    //jip酒店订单校验
                    orderHeadList = list(new QueryWrapper<OrderHead>()
                            .eq(OrderHead.USER_ID, param.getUserId())
                            .eq(OrderHead.VIP_FLAG, OrderVipFlagEnum.JIP.getValue())
                            .in(OrderHead.STATUS
                                    , OrderStatus.prePay
                                    , OrderStatus.preCheckIn
                                    , OrderStatus.living
                            )
                    );
                    if (null != orderHeadList && orderHeadList.size() > 0) {
                        throw new ServiceException("同一时间只能订一间房间");
                    }
                }
                break;
            //v3.4 b2c
            case 2:
                break;
            //v3.4 c2b抢单
            case 10:
                //校验是否有timestamp
                if (Objects.isNull(param.getTimestamp())) {
                    throw new ServiceException("非抢单订单,请重试");
                }
                long timeDifference = System.currentTimeMillis() - param.getTimestamp();
                //校验时间戳
                //校验下单时间是否超时
                if (timeDifference > (8 * 60 * 1000)) {
                    throw new ServiceException("超过允许下单的时间");
                }
                //校验抢单记录
                orderPickRecord = orderPickRecordService.getOne(
                        new QueryWrapper<OrderPickRecord>()
                                .eq(OrderPickRecord.USER_ID, param.getUserId())
                                .eq(OrderPickRecord.TIMESTAMP, param.getTimestamp())
                                .eq(OrderPickRecord.ROOM_ID, param.getRoomId())
                                .last("limit 1")
                );
                if (Objects.isNull(orderPickRecord)) {
                    throw new ServiceException("抢单记录不存在");
                }
                break;
        }
        //房间信息
        RoomInfo roomInfo = RoomInfoService.getOne(new QueryWrapper<RoomInfo>()
                .eq(RoomInfo.ID, param.getRoomId()).eq(RoomInfo.IS_DEL, 1));
        if (null == roomInfo) {
            throw new ServiceException("房间信息不正确");
        }
        switch (param.getVipFlag()) {
            //c2b
            case 0:
                //v3.4 b2c
            case 2:
                //v3.4 c2b抢单
            case 10:
                if (Objects.equals(0, roomInfo.getValid())) {
                    throw new ServiceException("房间未上架");
                }
                break;
            case 1:
                if (!Objects.equals(1, roomInfo.getVipFlag())) {
                    throw new ServiceException("非甄选房间");
                }
                if (Objects.equals(0, roomInfo.getVipStatus())) {
                    throw new ServiceException("房间不可用");
                }
                break;
            //jip
            case 3:
                if (!Objects.equals(3, roomInfo.getVipFlag())) {
                    throw new ServiceException("非精选房间");
                }
                if (Objects.equals(0, roomInfo.getVipStatus())) {
                    throw new ServiceException("房间不可用");
                }
                break;
        }
        //酒店信息
        HotelInfo hotelInfo = hotelInfoService.getById(roomInfo.getHotelId());
        if (Objects.isNull(hotelInfo)
                || Objects.equals(0, hotelInfo.getIsDel())
                || Objects.equals(0, hotelInfo.getValid())
                || !Objects.equals(3, hotelInfo.getStatus())) {
            throw new ServiceException("酒店信息不正确");
        }
        //v3.4 每日下单优惠券限制
        switch (param.getVipFlag()) {
            //c2b
            case 0:
            case 2:
            case 10:
                if (Objects.nonNull(param.getUserCouponInfoId())) {
                    Integer couponEnablePerDay = getCouponEnablePerDay();
                    //一天只能使用一张优惠券
                    if (!checkOrderUserCouponInfoCount(param.getUserId(), couponEnablePerDay)) {
                        throw new ServiceException(String.format("每天只能使用%d张优惠券", couponEnablePerDay));
                    }
                    //jip酒店才可以用优惠券
//                    if (!checkOrderUserCouponInfoHotelCanBeUse(param.getUserId(), hotelInfo.getId(), param.getUserCouponInfoId())) {
//                        throw new ServiceException("优惠券使用范围有误");
//                    }
                }
                break;
        }
        //房态信息
        List<RoomCalendarInfo> roomCalendarInfos = CollectionUtil.list(false);
        List<RoomCalendarVipInfo> roomCalendarVipInfos = CollectionUtil.list(false);
        List<RoomCalendarJipInfo> roomCalendarJipInfos = CollectionUtil.list(false);
        switch (param.getVipFlag()) {
            //v3.3 c2b
            case 0:
                //v3.4 b2c
            case 2:
                //v3.4 c2b抢单
            case 10:
                roomCalendarInfos = roomCalendarInfoService.list(new QueryWrapper<RoomCalendarInfo>()
                        .eq(RoomCalendarInfo.ROOM_ID, param.getRoomId())
                        .ge(RoomCalendarInfo.DATE, param.getStartDate())
                        .lt(RoomCalendarInfo.DATE, param.getEndDate()));
                if (null == roomCalendarInfos || roomCalendarInfos.size() != days) {
                    throw new ServiceException("房态信息不正确");
                }
                //v3.3 c2b需要判断价格
                switch (param.getVipFlag()) {
                    case 0:
                        for (RoomCalendarInfo roomCalendarInfo : roomCalendarInfos) {
                            if (param.getPrice() > roomCalendarInfo.getSalePrice() || param.getPrice() < roomCalendarInfo.getBottomPrice()) {
                                throw new ServiceException("抢单价错误");
                            }
                        }
                        break;
                }
                //检查剩余房间数量
                for (RoomCalendarInfo roomCalendarInfo : roomCalendarInfos) {
                    if (Objects.equals(0, roomCalendarInfo.getStatus())) {
                        throw new ServiceException("房间数量不足");
                    }
                    if (roomCalendarInfo.getCount() < param.getRoomCount()) {
                        throw new ServiceException("房间数量不足");
                    }
                }
                break;
            //vip
            case 1:
                roomCalendarVipInfos = roomCalendarVipInfoService.list(new QueryWrapper<RoomCalendarVipInfo>()
                        .eq(RoomCalendarVipInfo.ROOM_ID, param.getRoomId())
                        .ge(RoomCalendarVipInfo.DATE, param.getStartDate())
                        .lt(RoomCalendarVipInfo.DATE, param.getEndDate()));
                if (null == roomCalendarVipInfos || roomCalendarVipInfos.size() != days) {
                    throw new ServiceException("房态信息不正确");
                }
                //检查剩余房间数量
                for (RoomCalendarVipInfo roomCalendarVipInfo : roomCalendarVipInfos) {
                    if (Objects.equals(0, roomCalendarVipInfo.getStatus())) {
                        throw new ServiceException("房间数量不足");
                    }
                    if (roomCalendarVipInfo.getCount() < param.getRoomCount()) {
                        throw new ServiceException("房间数量不足");
                    }
                }
                break;
            //jip
            case 3:
                roomCalendarJipInfos = roomCalendarJipInfoService.list(new QueryWrapper<RoomCalendarJipInfo>()
                        .eq(RoomCalendarJipInfo.ROOM_ID, param.getRoomId())
                        .ge(RoomCalendarJipInfo.DATE, param.getStartDate())
                        .lt(RoomCalendarJipInfo.DATE, param.getEndDate()));
                if (null == roomCalendarJipInfos || roomCalendarJipInfos.size() != days) {
                    throw new ServiceException("房态信息不正确");
                }
                //检查剩余房间数量
                for (RoomCalendarJipInfo roomCalendarJipInfo : roomCalendarJipInfos) {
                    if (Objects.equals(0, roomCalendarJipInfo.getStatus())) {
                        throw new ServiceException("房间数量不足");
                    }
                    if (roomCalendarJipInfo.getCount() < param.getRoomCount()) {
                        throw new ServiceException("房间数量不足");
                    }
                }
                break;
        }
        //订单号
        String orderNo = IdWorkerUtil.nextStrId();
        //添加类别
        switch (param.getVipFlag()) {
            //c2b
            case 0:
            case 10:
                orderNo = "c2b" + orderNo;
                break;
            //vip
            case 1:
                orderNo = "vip" + orderNo;
                break;
            //jip
            case 3:
                orderNo = "jip" + orderNo;
                break;
            //v3.4 b2c
            case 2:
                orderNo = "b2c" + orderNo;
                break;
        }
        //添加来源
        if (StrUtil.isBlank(param.getSourceType())) {
            orderNo = HotelSourceType.YYKS + orderNo;
        } else {
            orderNo = param.getSourceType() + orderNo;
        }
        //最终付款
        Integer snapshotOriginTotalFee = 0;
        switch (param.getVipFlag()) {
            //c2b
            case 0:
                snapshotOriginTotalFee = param.getPrice() * days.intValue() * param.getRoomCount();
                break;
            //vip
            case 1:
                for (RoomCalendarVipInfo roomCalendarVipInfo : roomCalendarVipInfos) {
                    snapshotOriginTotalFee += roomCalendarVipInfo.getSalePrice() * param.getRoomCount();
                }
                break;
            //jip
            case 3:
                for (RoomCalendarJipInfo roomCalendarJipInfo : roomCalendarJipInfos) {
                    snapshotOriginTotalFee += roomCalendarJipInfo.getSalePrice() * param.getRoomCount();
                }
                break;
            //v3.4 b2c
            case 2:
                for (RoomCalendarInfo roomCalendarInfo : roomCalendarInfos) {
                    snapshotOriginTotalFee += roomCalendarInfo.getSalePrice() * param.getRoomCount();
                }
                break;
            //v3.4 c2b抢单
            case 10:
                snapshotOriginTotalFee = orderPickRecord.getUserShowPrice() * days.intValue() * param.getRoomCount();
                break;
        }
        //利润
        Integer vipProfit = null;
        BigDecimal discount;
        Integer totelPurcPrice;
        switch (param.getVipFlag()) {
            //vip
            case 1:
                discount = Convert.toBigDecimal(configService.getValue(ConfigKey.DISCOUNT), new BigDecimal(50));
                totelPurcPrice = 0;
                for (RoomCalendarVipInfo roomCalendarVipInfo : roomCalendarVipInfos) {
                    totelPurcPrice += roomCalendarVipInfo.getPurcPrice();
                }
                vipProfit = discount
                        .divide(new BigDecimal(100))
                        .multiply(new BigDecimal(snapshotOriginTotalFee))
                        .subtract(new BigDecimal(totelPurcPrice))
                        .intValue();
                //jip
            case 3:
                discount = Convert.toBigDecimal(configService.getValue(ConfigKey.DISCOUNT_JIP), new BigDecimal(66));
                totelPurcPrice = 0;
                for (RoomCalendarJipInfo roomCalendarJipInfo : roomCalendarJipInfos) {
                    totelPurcPrice += roomCalendarJipInfo.getPurcPrice();
                }
                vipProfit = discount
                        .divide(new BigDecimal(100))
                        .multiply(new BigDecimal(snapshotOriginTotalFee))
                        .subtract(new BigDecimal(totelPurcPrice))
                        .intValue();
        }
        if (Objects.nonNull(vipProfit) && vipProfit < 0) {
            vipProfit = 0;
        }
        //生成订单
        OrderHead orderHead = new OrderHead();
        Date createTime = new Date();
        orderHead.setGmtCreate(createTime);
        orderHead.setGmtModified(createTime);
        orderHead.setOrderNo(orderNo);
        orderHead.setUserId(param.getUserId());
        orderHead.setRoomId(param.getRoomId());
        orderHead.setHotelId(hotelInfo.getId());
        orderHead.setSnapshotHotelName(hotelInfo.getName());
        orderHead.setSnapshotRoomName(roomInfo.getTitle());
        orderHead.setSnapshotOriginTotalFee(snapshotOriginTotalFee);
        orderHead.setStatus(1);
        orderHead.setCheckIn(param.getStartDate());
        orderHead.setCheckOut(param.getEndDate());
        orderHead.setDays(days.intValue());
        orderHead.setRoomCount(param.getRoomCount());
        orderHead.setContactName(param.getConsumerName());
        orderHead.setContactPhone(param.getConsumerPhone());
        orderHead.setVipProfit(vipProfit);
        orderHead.setDeleteFlag(0);
        orderHead.setProvinceAgentId(hotelInfo.getProvinceAgentId());
        orderHead.setCityAgentId(hotelInfo.getCityAgentId());
        orderHead.setAreaAgentId(hotelInfo.getAdminId());
        orderHead.setVipFlag(param.getVipFlag());
        //3.4的抢单订单类型和3.3的c2b一样
        if (Objects.equals(param.getVipFlag(), 10)) {
            orderHead.setVipFlag(0);
        }
        orderHead.setFeeValue(0);
        orderHead.setLeaveMessage(param.getLeaveMessage());
        orderHead.setYeyuRate(hotelInfo.getParentTax() * 10);
        String hotelExt = hotelInfo.getExtraInfo();
        String roomExt = roomInfo.getExtraInfo();
        //填充附加信息
        HashMap<String, Object> map = new HashMap<>();
        TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.HOTEL_ADDRESS, hotelInfo.getAddress()));
        TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.HOTEL_PHONE, hotelInfo.getPhone()));
        TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.HOTEL_TEL, hotelInfo.getTel()));
        TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.HOTEL_IMG_URLS, JSONUtil.parseObj(hotelExt).getJSONArray("imgUrlList").toList(String.class)));
        TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.ROOM_IMG_URLS, JSONUtil.parseObj(roomExt).getJSONArray("imgUrlList").toList(String.class)));
        if (Objects.equals(param.getVipFlag(), 10)) {
            TryCatchUtil.tryCatch(() -> map.put(OrderHeadExtraInfoConstant.GRAB_THE_ORDER_TIMESTAMP, param.getTimestamp()));
        }
        orderHead.setExtraInfo(JSONUtil.toJsonStr(map));
        Integer snapshotTotalFee = snapshotOriginTotalFee;
        //优惠券信息
        switch (param.getVipFlag()) {
            //c2b
            case 0:
                //v3.4 b2c
            case 2:
                //v3.4 c2b抢单
            case 10:
                if (null != param.getUserCouponInfoId()) {
                    if (Objects.equals(0, hotelInfo.getEnabledCoupon())) {
                        throw new ServiceException("该酒店不能使用优惠券");
                    }
                    UserCouponInfo userCouponInfo = userCouponInfoService.getOne(new QueryWrapper<UserCouponInfo>()
                            .eq(UserCouponInfo.ID, param.getUserCouponInfoId()).eq(UserCouponInfo.USER_ID, param.getUserId())
                            .eq(UserCouponInfo.USED, 0));
                    if (null == userCouponInfo) {
                        throw new ServiceException("优惠券不存在");
                    }
                    if (0 != userCouponInfo.getUsed()) {
                        throw new ServiceException("优惠券非未使用状态");
                    }
                    if (userCouponInfo.getOverTime().before(new Date())) {
                        throw new ServiceException("优惠券已经过期");
                    }
                    orderHead.setUserCouponId(userCouponInfo.getId());
                    CouponInfo couponInfo = couponInfoService.getById(userCouponInfo.getCouponId());
                    if (snapshotOriginTotalFee < couponInfo.getValidFee()) {
                        throw new ServiceException("优惠券未达到使用条件");
                    }
                    //设置优惠后的金额
                    snapshotTotalFee -= userCouponInfo.getCouponValue();
                    if (snapshotTotalFee < 1) {
                        snapshotTotalFee = 1;
                    }
                    //锁定优惠券
                    UserCouponInfo userCouponInfoNew = new UserCouponInfo()
                            .setId(userCouponInfo.getId()).setUsed(UserCouponInfoStatus.LOCK.value());
                    boolean b = userCouponInfoService.updateById(userCouponInfoNew);
                    if (!b) {
                        throw new ServiceException("优惠券更新失败");
                    }
                }
                break;
            //vip
            case 1:
                //jip
            case 3:
                //vip和jip不允许使用优惠券
                break;
        }
        orderHead.setSnapshotTotalFee(snapshotTotalFee);
        //会员卡信息
        switch (param.getVipFlag()) {
            //vip
            case 1:
            case 3:
                try {
                    Integer cardType = VipCardTypeEnum.getCardTypeByOrderVipFlagValue(param.getVipFlag());
                    UserMemberCard userMemberCard = userMemberCardService.getUserMemberCard(param.getUserId(), cardType);
                    if (Objects.isNull(userMemberCard)) {
                        throw new ServiceException("非会员");
                    }
                    MemberCard memberCard = memberCardService.getOne(new QueryWrapper<MemberCard>()
                            .eq(MemberCard.ID, userMemberCard.getCardId())
                            .eq(MemberCard.ENABLE, 1)
                            .eq(MemberCard.STATUS, 2)
                            .last("limit 1")
                    );
                    if (Objects.isNull(memberCard)) {
                        throw new ServiceException("会员卡不存在");
                    }
                    orderHead.setMemberCardNo(memberCard.getCardNo());
                    orderHead.setSalerId(memberCard.getSalerId());
                    orderHead.setSalerType(memberCard.getSalerType());
                } catch (Exception e) {
                    if (e instanceof ServiceException) {
                        throw e;
                    } else {
                        e.printStackTrace();
                        throw new ServiceException("会员卡记录失败");
                    }
                }
                break;
        }


        //联合订单参数
        orderHead.setSourceType(HotelSourceType.YYKS);
        orderHead.setSourceHotelId(String.valueOf(hotelInfo.getId()));
        orderHead.setSourceRoomId(String.valueOf(roomInfo.getId()));


        //添加省市名称
        //省名称
        TryCatchUtil.tryCatch(() -> {
            AccountInfo accountInfo = accountInfoService.getOne(
                    new QueryWrapper<AccountInfo>()
                            .eq(AccountInfo.ID, hotelInfo.getProvinceAgentId())
            );
            if (Objects.nonNull(accountInfo)) {
                orderHead.setProvinceName(accountInfo.getArea());
            }
        });
        //市名称
        TryCatchUtil.tryCatch(() -> {
            AccountInfo accountInfo = accountInfoService.getOne(
                    new QueryWrapper<AccountInfo>()
                            .eq(AccountInfo.ID, hotelInfo.getCityAgentId())
            );
            if (Objects.nonNull(accountInfo)) {
                String[] split = accountInfo.getArea().split("\\.");
                orderHead.setCityName(split[1]);
            }
        });


        //添加订单
        int createOrder = baseMapper.insert(orderHead);
        if (createOrder < 1) {
            throw new ServiceException("添加订单失败");
        }
        //添加订单详情
        ArrayList<OrderBill> orderBills = new ArrayList<>();
        switch (param.getVipFlag()) {
            //c2b
            case 0:
                //v3.4 b2c
            case 2:
                //v3.4 c2b抢单
            case 10:
                for (RoomCalendarInfo roomCalendarInfo : roomCalendarInfos) {
                    OrderBill orderBill = new OrderBill();
                    orderBill.setOrderNo(orderHead.getOrderNo());
                    orderBill.setInDate(roomCalendarInfo.getDate());
                    orderBill.setOriginPrice(roomCalendarInfo.getOriginPrice());
                    orderBill.setSalePrice(roomCalendarInfo.getSalePrice());
                    switch (param.getVipFlag()) {
                        //c2b
                        case 0:
                            orderBill.setDealPrice(param.getPrice());
                            break;
                        //v3.4 b2c
                        case 2:
                            orderBill.setDealPrice(roomCalendarInfo.getSalePrice());
                            break;
                        //v3.4 c2b抢单
                        case 10:
                            orderBill.setDealPrice(orderPickRecord.getUserShowPrice());
                            break;
                    }
                    orderBill.setBottomPrice(roomCalendarInfo.getBottomPrice());
                    orderBill.setRoomCount(param.getRoomCount());
                    orderBill.setHotelExtraInfo(JSONUtil.toJsonStr(hotelInfo));
                    orderBill.setRoomExtraInfo(JSONUtil.toJsonStr(roomInfo));
                    orderBill.setRoomCalendarInfo(JSONUtil.toJsonStr(roomCalendarInfo));
                    orderBill.setGmtCreate(new Date());
                    orderBills.add(orderBill);
                }
                break;
            //vip
            case 1:
                for (RoomCalendarVipInfo roomCalendarVipInfo : roomCalendarVipInfos) {
                    OrderBill orderBill = new OrderBill();
                    orderBill.setOrderNo(orderHead.getOrderNo());
                    orderBill.setInDate(roomCalendarVipInfo.getDate());
                    orderBill.setOriginPrice(null);
                    orderBill.setSalePrice(roomCalendarVipInfo.getSalePrice());
                    orderBill.setDealPrice(roomCalendarVipInfo.getSalePrice());
                    orderBill.setBottomPrice(null);
                    orderBill.setRoomCount(param.getRoomCount());
                    orderBill.setHotelExtraInfo(JSONUtil.toJsonStr(hotelInfo));
                    orderBill.setRoomExtraInfo(JSONUtil.toJsonStr(roomInfo));
                    orderBill.setRoomCalendarInfo(JSONUtil.toJsonStr(roomCalendarVipInfo));
                    orderBill.setGmtCreate(new Date());
                    orderBills.add(orderBill);
                }
                break;
            //jip
            case 3:
                for (RoomCalendarJipInfo roomCalendarJipInfo : roomCalendarJipInfos) {
                    OrderBill orderBill = new OrderBill();
                    orderBill.setOrderNo(orderHead.getOrderNo());
                    orderBill.setInDate(roomCalendarJipInfo.getDate());
                    orderBill.setOriginPrice(null);
                    orderBill.setSalePrice(roomCalendarJipInfo.getSalePrice());
                    orderBill.setDealPrice(roomCalendarJipInfo.getSalePrice());
                    orderBill.setBottomPrice(null);
                    orderBill.setRoomCount(param.getRoomCount());
                    orderBill.setHotelExtraInfo(JSONUtil.toJsonStr(hotelInfo));
                    orderBill.setRoomExtraInfo(JSONUtil.toJsonStr(roomInfo));
                    orderBill.setRoomCalendarInfo(JSONUtil.toJsonStr(roomCalendarJipInfo));
                    orderBill.setGmtCreate(new Date());
                    orderBills.add(orderBill);
                }
                break;
        }
        boolean b = orderBillService.saveBatch(orderBills);
        if (!b) {
            throw new ServiceException("添加订单详情失败");
        }
        //更新房态
        switch (param.getVipFlag()) {
            //c2b
            case 0:
                //v3.4 b2c
            case 2:
                //v3.4 c2b抢单
            case 10:
                for (RoomCalendarInfo roomCalendarInfo : roomCalendarInfos) {
                    boolean update = roomCalendarInfoService.update(new UpdateWrapper<RoomCalendarInfo>()
                            .set(RoomCalendarInfo.COUNT, roomCalendarInfo.getCount() - param.getRoomCount())
                            .set(RoomCalendarInfo.LOCK_COUNT, roomCalendarInfo.getLockCount() + param.getRoomCount())
                            .eq(RoomCalendarInfo.ID, roomCalendarInfo.getId())
                            .eq(RoomCalendarInfo.COUNT, roomCalendarInfo.getCount())
                            .eq(RoomCalendarInfo.LOCK_COUNT, roomCalendarInfo.getLockCount()));
                    if (!update) {
                        throw new ServiceException("更新房态失败");
                    }
                }
                break;
            //vip
            case 1:
                for (RoomCalendarVipInfo roomCalendarVipInfo : roomCalendarVipInfos) {
                    boolean update = roomCalendarVipInfoService.update(new UpdateWrapper<RoomCalendarVipInfo>()
                            .set(RoomCalendarVipInfo.COUNT, roomCalendarVipInfo.getCount() - param.getRoomCount())
                            .set(RoomCalendarVipInfo.LOCK_COUNT, roomCalendarVipInfo.getLockCount() + param.getRoomCount())
                            .eq(RoomCalendarVipInfo.ID, roomCalendarVipInfo.getId())
                            .eq(RoomCalendarVipInfo.COUNT, roomCalendarVipInfo.getCount())
                            .eq(RoomCalendarVipInfo.LOCK_COUNT, roomCalendarVipInfo.getLockCount()));
                    if (!update) {
                        throw new ServiceException("更新房态失败");
                    }
                }
                break;
            //Jip
            case 3:
                for (RoomCalendarJipInfo roomCalendarJipInfo : roomCalendarJipInfos) {
                    boolean update = roomCalendarJipInfoService.update(new UpdateWrapper<RoomCalendarJipInfo>()
                            .set(RoomCalendarJipInfo.COUNT, roomCalendarJipInfo.getCount() - param.getRoomCount())
                            .set(RoomCalendarJipInfo.LOCK_COUNT, roomCalendarJipInfo.getLockCount() + param.getRoomCount())
                            .eq(RoomCalendarJipInfo.ID, roomCalendarJipInfo.getId())
                            .eq(RoomCalendarJipInfo.COUNT, roomCalendarJipInfo.getCount())
                            .eq(RoomCalendarJipInfo.LOCK_COUNT, roomCalendarJipInfo.getLockCount()));
                    if (!update) {
                        throw new ServiceException("更新房态失败");
                    }
                }
                break;
        }
        //发送订单超时检查消息
        mqProducerService.sendOrderCheckToWebMessage(new OrderCheckToWebMessage().setOrderNo(orderNo));
        OrderHeadC2bPlaceAnOrderVo orderHeadc2bPlaceAnOrderVo = new OrderHeadC2bPlaceAnOrderVo();
        orderHeadc2bPlaceAnOrderVo.setOrderNo(orderNo);
        return orderHeadc2bPlaceAnOrderVo;
    }

    @Override
    public OrderHeadFindNoPayOrderVo findNoFinishOrder(OrderHeadFindNoPayOrderParam param) {
        //jip酒店订单校验
        OrderHead orderHead = getOne(new QueryWrapper<OrderHead>()
                .eq(OrderHead.USER_ID, param.getUserId())
                .eq(OrderHead.VIP_FLAG, param.getVipFlag())
                .in(OrderHead.STATUS
                        , OrderStatus.prePay
                        , OrderStatus.preCheckIn
                        , OrderStatus.living
                )
                .orderByDesc(OrderHead.GMT_CREATE)
                .last("limit 1")
        );
        OrderHeadFindNoPayOrderVo orderHeadFindNoPayOrderVo = new OrderHeadFindNoPayOrderVo();
        if (Objects.nonNull(orderHead)) {
            orderHeadFindNoPayOrderVo.setOrderNo(orderHead.getOrderNo());
        }
        return orderHeadFindNoPayOrderVo;
    }

    /**
     * 统计查询订单总额和订单数
     *
     * @param loginUser
     * @param param
     * @return
     */
    @Override
    public StatisticalResult statFee(AccountInfo loginUser, StatisticalParam param) {
        //根据登录账户获取该账户下的酒店
        List<Integer> hotelIds = hotelInfoService.getHotelInfoByAccountIdToId(loginUser);
        StatisticalResult result = new StatisticalResult();
        if (hotelIds == null || hotelIds.size() == 0) {
            return result;
        }
        Map<String, Object> map = Maps.newHashMap();
        if (loginUser.getType() != AccountType.Administrator) {
            map.put("hotelIds", hotelIds);
        }
        map.put("orderStart", new Date(param.getOrderStart()));
        map.put("orderEnd", new Date(param.getOrderEnd()));
        if (null != param.getVipFlag()) {
            map.put("vipFlags", Splitters.splitToInteger(param.getVipFlag(), Splitters.COMMA));
        }
        return baseMapper.statFee(map);
    }

    /**
     * 根据时间和类型统计
     *
     * @param startTime
     * @param endTime
     * @param type
     * @return
     */
    private StatisticalResult statFee(Long startTime, Long endTime, String type) {
        Map<String, Object> map = Maps.newHashMap();
        map.put("orderStart", new Date(startTime));
        map.put("orderEnd", new Date(endTime));
        if (null != type) {
            map.put("vipFlags", Splitters.splitToInteger(type, Splitters.COMMA));
        }
        return baseMapper.statFee(map);
    }

    /**
     * 统计月和日
     *
     * @param loginUser
     * @param type
     * @return
     */
    @Override
    public List<StatisticalResult> statMonthAndDay(AccountInfo loginUser, Integer type, String vipFlag) {
        //根据登录账户获取该账户下的酒店
        List<Integer> hotelIds = hotelInfoService.getHotelInfoByAccountIdToId(loginUser);
        if (hotelIds == null || hotelIds.size() == 0) {
            return Lists.newArrayList();
        }
        Map<String, Object> map = Maps.newHashMap();
        if (loginUser.getType() != AccountType.Administrator) {
            map.put("hotelIds", hotelIds);
        }
        map.put("type", type);
        LocalDate nowLocalDate = LocalDate.now();
        Date nowDate = new Date();
        //获取当月开始时间
        DateTime beginOfMonth = DateUtil.beginOfMonth(nowDate);
        //获取当月的结束时间
        DateTime endOfMonth = DateUtil.endOfMonth(nowDate);
        DateTime sevenBeginOfMonth = DateUtil.offsetMonth(beginOfMonth, -7);
        //月统计
        if (1 == type) {
            map.put("orderStart", sevenBeginOfMonth);
            map.put("orderEnd", endOfMonth);
        } else {
            map.put("orderStart", nowLocalDate.minusDays(7));
            map.put("orderEnd", DateUtils.localDateToDate(nowLocalDate));
        }
        map.put("vipFlags", Splitters.splitToInteger(vipFlag, Splitters.COMMA));
        return baseMapper.statMonthAndDay(map);
    }

    @Override
    public int orderCount(Integer hotelId, Integer vipFlag, Integer status) {
        QueryWrapper<OrderHead> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(OrderHead.HOTEL_ID, hotelId);
        queryWrapper.eq(OrderHead.VIP_FLAG, vipFlag);
        queryWrapper.eq(OrderHead.STATUS, status);
        return baseMapper.selectCount(queryWrapper);
    }

    /**
     * 分页获取订单
     *
     * @param loginUser
     * @param param
     * @return
     */
    @Override
    public PageResult<OrderListResult> myList(AccountInfo loginUser, OrderListParam param) {
        Map<String, Object> paramMap = getOrderHeadMap(loginUser, param);
        List<Integer> hotelIds = getHotelIdsByAccountId(AccountUtil.getOperationUserId(loginUser), loginUser.getType());
        if (null == hotelIds || 0 == hotelIds.size()) {
            hotelIds = Lists.newArrayList(-1);
        }
        paramMap.put("hotelIds", hotelIds);
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<OrderHead> orderHeads = baseMapper.myList(paramMap);
        Map<Integer, UserInfo> userInfoMap = getUserInfoMap(orderHeads);
        PageInfo<OrderHead> pageInfo = PageInfo.of(orderHeads);
        List<OrderListResult> orderListResults = null;
        //vip
        if (param.getVipFlag().contains("3")) {
            orderListResults = getOrderListResult(orderHeads, userInfoMap, loginUser.getType(), loginUser.getId());
        } else {
            orderListResults = getOrderListResult(orderHeads, userInfoMap, null, null);
        }
        return new PageResult<>(pageInfo.getTotal(), pageInfo.getPages(), pageInfo.isHasNextPage(), pageInfo.getNextPage(), orderListResults);
    }

    private Map<String, Object> getOrderHeadMap(AccountInfo loginUser, OrderListParam param) {
        Map<String, Object> paramMap = Maps.newHashMap();
        List<Integer> statusList = null;
        if (param.getStatus() != null) {
            statusList = Splitters.splitToInteger(param.getStatus(), Splitters.COMMA);
        }
        paramMap.put("statusList", statusList);
        paramMap.put("orderNo", param.getOrderNo());
        Date startDate = DateUtils.yyyyMMddToDate(param.getOrderDate());
        paramMap.put("startTime", startDate);
        if (null != startDate) {
            Date endDate = DateUtils.afterDaysToDate(startDate, 1L);
            paramMap.put("endTime", endDate);
        }
        paramMap.put("checkIn", DateUtils.yyyyMMddToDate(param.getCheckIn()));
        paramMap.put("checkOut", DateUtils.yyyyMMddToDate(param.getCheckOut()));
        paramMap.put("type", loginUser.getType());
        paramMap.put("id", AccountUtil.getOperationUserId(loginUser));
        paramMap.put("area", param.getArea());
        paramMap.put("hotelName", param.getHotelName());
        paramMap.put("name", param.getName());
        paramMap.put("sourceType", param.getSourceType());
        if (null != param.getVipFlag()) {
            paramMap.put("vipFlags", Splitters.splitToInteger(param.getVipFlag(), Splitters.COMMA));
        }
        if (null != param.getUserPhone()) {
            if (!TextValidator.MOBILE.boolCheck(param.getUserPhone())) {
                throw new ServiceException("下单用户手机号格式有误");
            }
            //通过下单手机号查询用户id
            UserInfo userInfo = userInfoService.selectUseInfoPhone(param.getUserPhone());
            Arguments.beanIsNull(userInfo, "下单用户手机号不存在");
            paramMap.put("userId", userInfo.getId());
        }
        return paramMap;
    }

    private Map<Integer, UserInfo> getUserInfoMap(List<OrderHead> orderHeads) {
        if (null == orderHeads || orderHeads.size() == 0) {
            return Maps.newHashMap();
        }
        Set<OrderHead> set = new TreeSet<>(Comparator.comparing(OrderHead::getUserId));
        set.addAll(orderHeads);
        List<OrderHead> collect = Lists.newArrayList(set);
        try {
            List<Integer> userIds = Lists.transform(collect, OrderHead::getUserId);
            List<UserInfo> userInfos = userInfoService.list(new QueryWrapper<UserInfo>().in(UserInfo.ID, userIds));
            return Maps.uniqueIndex(userInfos, UserInfo::getId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Maps.newHashMap();
    }

//    /**
//     * 订单对象转换
//     *
//     * @param orderHeads
//     * @return
//     */
//    private List<OrderListResult> getOrderListResult(List<OrderHead> orderHeads, Map<Integer, UserInfo> userInfoMap) {
//        List<OrderListResult> orderListResults = Lists.newArrayList();
//        Map<Integer, HotelInfo> hotelInfoMap = getHotelInfoMap(orderHeads);
//        for (OrderHead orderHead : orderHeads) {
//            OrderListResult orderListResult = ObjectConvertUtil.convertObject(orderHead, OrderListResult.class);
//            if (null != orderListResult) {
//                orderListResult.setOrderTotalFee(orderHead.getSnapshotOriginTotalFee());
//                orderListResult.setPhone(orderHead.getContactPhone());
//                orderListResult.setName(orderHead.getContactName());
//                //酒店图片
//                HotelInfo hotelInfo = hotelInfoMap.get(orderHead.getHotelId());
//                if (null != hotelInfo) {
//                    orderListResult.setHotelPics(getHotelPics(hotelInfo));
//                } else {
//                    log.info("订单对应的酒店不存在hotelId = {}", orderHead.getHotelId());
//                }
//                //优惠券金额
//                orderListResult.setCouponValue(getCouponPrice(orderHead));
//                UserInfo userInfo = userInfoMap.get(orderHead.getUserId());
//                if (null != userInfo) {
//                    orderListResult.setUserPhone(userInfo.getPhone());
//                }
//                orderListResults.add(orderListResult);
//            }
//        }
//        return orderListResults;
//    }

    /**
     * 订单对象转换
     *
     * @param orderHeads
     * @param type
     * @return
     */
    private List<OrderListResult> getOrderListResult(List<OrderHead> orderHeads, Map<Integer, UserInfo> userInfoMap, Integer type, Integer accountId) {
        List<OrderListResult> orderListResults = Lists.newArrayList();
        Map<Integer, HotelInfo> hotelInfoMap = getHotelInfoMap(orderHeads);
        for (OrderHead orderHead : orderHeads) {
            OrderListResult orderListResult = ObjectConvertUtil.convertObject(orderHead, OrderListResult.class);
            if (null != orderListResult) {
                orderListResult.setOrderTotalFee(orderHead.getSnapshotOriginTotalFee());
                orderListResult.setPhone(orderHead.getContactPhone());
                orderListResult.setName(orderHead.getContactName());
                //酒店图片
                HotelInfo hotelInfo = hotelInfoMap.get(orderHead.getHotelId());
                if (null != hotelInfo) {
                    orderListResult.setHotelPics(getHotelPics(hotelInfo));
                } else {
                    log.info("订单对应的酒店不存在hotelId = {}", orderHead.getHotelId());
                }
                //优惠券金额
                orderListResult.setCouponValue(getCouponPrice(orderHead));
                UserInfo userInfo = userInfoMap.get(orderHead.getUserId());
                if (null != userInfo) {
                    orderListResult.setUserPhone(userInfo.getPhone());
                }
                //如果vip需要展示vip分佣字段
                if (null != type && null != accountId && orderHead.getVipFlag() == 3) {
                    if (orderHead.getStatus().equals(OrderStatus.postCheckOut)
                            || orderHead.getStatus().equals(OrderStatus.comment))
                        orderListResult.setVipCommissionAmount(getVipCommissionAmount(type, accountId, orderHead.getOrderNo()));
                }
                orderListResults.add(orderListResult);
            }
        }
        return orderListResults;
    }

    /**
     * 通过账户类型获取vip分佣金额
     *
     * @param type      账户类型
     * @param accountId 账户id
     * @param orderNo   订单号
     * @return
     */
    private Integer getVipCommissionAmount(Integer type, Integer accountId, String orderNo) {
        //根据账户类型设置分佣类型
        List<Integer> commissionTypes = Lists.newArrayList();
        //总公司直接return
        if (AccountType.Administrator == type) {
            return null;
        }
        //运营商
        if (AccountType.MinOperateMerchant == type) {
            commissionTypes.add(2); //卡运营商
            commissionTypes.add(6); //非卡运营商
        }
        //卡商
        if (AccountType.MinVipCardMerchant == type) {
            commissionTypes.add(9);
        }
        //酒店
        if (AccountType.HotelManager == type) {
            commissionTypes.add(1); //卡酒店
            commissionTypes.add(5); //非卡酒店
        }
        return miniVipCommissionBillService.getVipCommissionAmount(accountId, orderNo, commissionTypes);
    }

    /**
     * 获取订单中券的券面值
     *
     * @param orderHead
     * @return
     */
    @Override
    public Integer getCouponPrice(OrderHead orderHead) {
        try {
            Integer couponId = orderHead.getUserCouponId();
            if (couponId == null || couponId == 0) {
                return 0;
            }
            UserCouponInfo userCouponInfo = userCouponInfoService.getById(couponId);
            if (userCouponInfo != null) {
                CouponInfo couponInfo = couponInfoService.selectCouponInfo(userCouponInfo.getCouponId());
                if (couponInfo != null) {
                    if (CouponConst.free == couponInfo.getType()
                            || CouponConst.recommend == couponInfo.getType()) {
                        return userCouponInfo.getCouponValue();
                    } else {
                        return couponInfo.getPrice();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 通过订单获取酒店图片
     *
     * @param orderHead
     * @return
     */
    @Override
    public List<String> getHotelPics(OrderHead orderHead) {
        try {
            HotelInfo hotelInfo = hotelInfoService.getOne(new QueryWrapper<HotelInfo>().eq(HotelInfo.ID, orderHead.getHotelId()));
            String extraInfo = hotelInfo.getExtraInfo();
            HotelExtraInfo hotelExtraInfo = JSONObject.parseObject(extraInfo, HotelExtraInfo.class);
            return hotelExtraInfo.getImgUrlList();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Lists.newArrayList();
    }

    /**
     * 新订单退款
     *
     * @param operatorInfo
     * @param orderNo
     * @param accept
     * @param type
     */
    @Deprecated
    @Override
//    @Transactional(rollbackFor = Exception.class)
    public void refund(AccountInfo operatorInfo, String orderNo, Boolean accept, String type) {
        //根据这个值判断是否需要更新订单状态
        Boolean updateFlag = false;
        if (operatorInfo.getType() != AccountType.HotelManager && operatorInfo.getType() != AccountType.Administrator) {
            throw new ServiceException("当前用户无权操作");
        }
        OrderHead orderHead = baseMapper.selectOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, orderNo));
        if (orderHead == null) {
            throw new ServiceException("通过该订单号查询不到该订单");
        }
        if (RefundTypeEnum.USER.desc().equals(type) && !orderHead.getStatus().equals(OrderStatus.preRefund)) {
            throw new ServiceException("该订单非待退款状态");
        }
        if (RefundTypeEnum.HOTEL.desc().equals(type) && !orderHead.getStatus().equals(OrderStatus.preCheckIn)) {
            throw new ServiceException("该订单非待入住状态");
        }
        if (accept) {
            if (orderHead.getHotelId() == null || orderHead.getHotelId() == 0) {
                throw new ServiceException("订单中没有该酒店id");
            }
            HotelInfo hotelInfo = hotelInfoService.getById(orderHead.getHotelId());
            if (hotelInfo == null) {
                throw new ServiceException("没有该酒店信息");
            }
            //获取退款金额，商家点击退款全额退款，用户点击退款部分退
            Integer refundAmount = 0;
            if (type.equals(RefundTypeEnum.USER.desc())) {
                refundAmount = orderHead.getSnapshotRefundFee();
            }
            if (type.equals(RefundTypeEnum.HOTEL.desc())) {
                refundAmount = orderHead.getSnapshotTotalFee();
            }
            if (refundAmount == 0) {
                updateCouponAndRoomCount(orderHead);
                orderHead.setStatus(OrderStatus.postRefund);
            } else {
                updateFlag = refund(orderNo, refundAmount);
                if (updateFlag) {
                    orderHead.setStatus(OrderStatus.postRefund);
                }
            }
            if (updateFlag) {
                if (baseMapper.updateById(orderHead) != 1) {
                    throw new ServiceException("更新订单状态失败");
                }
                //发送相关短信
                refundSms(orderHead, type, hotelInfo);
            }
        } else {
            if (1 != baseMapper.update(null, new UpdateWrapper<OrderHead>().set(OrderHead.SNAPSHOT_REFUND_FEE, null)
                    .set(OrderHead.STATUS, OrderStatus.preCheckIn).eq(OrderHead.ORDER_NO, orderNo))) {
                throw new ServiceException("拒绝退款修改状态失败");
            }
            messageService.rejectRefund(orderHead.getUserId());
        }
    }

    /**
     * 新订单退款
     *
     * @param operatorInfo
     * @param orderNo
     */
    @Override
    public void refundWeb(AccountInfo operatorInfo, String orderNo) {
        //根据这个值判断是否需要更新订单状态
        boolean updateFlag = false;
        if (operatorInfo.getType() != AccountType.HotelManager && operatorInfo.getType() != AccountType.Administrator) {
            throw new ServiceException("当前用户无权操作");
        }
        OrderHead orderHead = baseMapper.selectOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, orderNo));
        if (orderHead == null) {
            throw new ServiceException("通过该订单号查询不到该订单");
        }
        if (!orderHead.getStatus().equals(OrderStatus.preCheckIn)) {
            throw new ServiceException("该订单非待入住状态");
        }
        //当前操作人为酒店账户，下单3分钟后无法点击无法接单按钮
        if (AccountType.HotelManager == operatorInfo.getType()) {
            Date overTime = DateUtils.dateAfterMinute(orderHead.getGmtCreate(), 3);
            if (DateUtils.dateCompareDate(new Date(), overTime)) {
                throw new ServiceException("下单时间三分钟后无法操作");
            }
        }
        if (orderHead.getHotelId() == null || orderHead.getHotelId() == 0) {
            throw new ServiceException("订单中没有该酒店id");
        }
        HotelInfo hotelInfo = hotelInfoService.getById(orderHead.getHotelId());
        if (hotelInfo == null) {
            throw new ServiceException("没有该酒店信息");
        }
        //获取退款金额，商家点击退款全额退款，用户点击退款部分退
        if (null == orderHead.getSnapshotTotalFee() || orderHead.getSnapshotTotalFee() == 0) {
            updateCouponAndRoomCount(orderHead);
            orderHead.setStatus(OrderStatus.postRefund);
        } else {
            updateFlag = refund(orderNo, orderHead.getSnapshotTotalFee());
            if (updateFlag) {
                orderHead.setStatus(OrderStatus.postRefund);
            }
        }
        if (updateFlag) {
            if (baseMapper.updateById(orderHead) != 1) {
                throw new ServiceException("更新订单状态失败");
            }
            //发送相关短信
            refundSms(orderHead, RefundTypeEnum.HOTEL.desc(), hotelInfo);
        }
    }

    /**
     * 导出订单
     *
     * @param loginUser
     * @param param
     * @return
     */
    @Override
    public List<OrderDownloadResult> selectDownloadOrder(AccountInfo loginUser, OrderDownParam param) {
        LocalDateTime now = LocalDateTime.now();
        if (Arguments.strIsNull(param.getStartTime()) && Arguments.strIsNull(param.getEndTime())) {
            param.setStartTime(DateUtils.formatYMDHMSStr(now.minusDays(7)));
            param.setEndTime(DateUtils.formatYMDHMSStr(now));
        }
        if (Arguments.strIsNull(param.getStartTime()) && Arguments.strNotNull(param.getEndTime())) {
            param.setStartTime(DateUtils.strAfterDaysToStr(param.getEndTime(), -7));
        }
        if (Arguments.strNotNull(param.getStartTime()) && Arguments.strIsNull(param.getEndTime())) {
            param.setEndTime(DateUtils.strAfterDaysToStr(param.getStartTime(), 7));
        }
        //如果时间大于一年，则导出去年这个点到当前这个点一年的数据
        if (null != param.getStartTime() && null != param.getEndTime() && DateUtils.getDayStrToInt(param.getStartTime(), param.getEndTime()) > 365) {
            param.setStartTime(DateUtils.formatYMDHMSStr(now.minusYears(1)));
            param.setEndTime(DateUtils.formatYMDHMSStr(now));
        }
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("dateStart", param.getStartTime());
        paramMap.put("dateEnd", param.getEndTime());
        if (Arguments.strNotNull(param.getArea())) {
            paramMap.put("area", param.getArea());
        }
        paramMap.put("type", loginUser.getType());
        paramMap.put("sourceType", param.getSourceType());
        paramMap.put("id", AccountUtil.getOperationUserId(loginUser));
        paramMap.put("timeType", param.getTimeType());
        paramMap.put("vipFlags", Splitters.splitToInteger(param.getVipFlag(), Splitters.COMMA));
        if (Arguments.strNotNull(param.getHotelName())) {
            paramMap.put("hotelName", param.getHotelName());
        }
        if (Arguments.strNotNull(param.getStatus())) {
            paramMap.put("statusList", Splitters.splitToInteger(param.getStatus(), Splitters.COMMA));
        } else {
            paramMap.put("statusList", null);
        }
        List<OrderHeadDownLoadResult> orderHeads = new ArrayList<>();
        if ("cn".equals(paramMap.get("sourceType"))) {
            orderHeads = baseMapper.selectDownloadCNOrder(paramMap);
        } else {
            orderHeads = baseMapper.selectDownloadOrder(paramMap);
        }
        return getOrderDownloadResult(orderHeads, param.getSourceType());
    }

    /**
     * 订单与导出订单对象转换
     *
     * @param orderHeads
     * @return
     */
    private List<OrderDownloadResult> getOrderDownloadResult(List<OrderHeadDownLoadResult> orderHeads, String sourceType) {
        List<OrderDownloadResult> orderDownloadResults = Lists.newArrayList();
        Map<String, OrderBill> orderBillMap = getOrderBillMap(orderHeads);
        for (OrderHeadDownLoadResult orderHead : orderHeads) {
            OrderDownloadResult orderDownloadResult = ObjectConvertUtil.convertObject(orderHead, OrderDownloadResult.class);
            if (null == orderDownloadResult) {
                continue;
            }
            orderDownloadResult.setGmtCreate(DateUtils.formatYMDHMSStr(orderHead.getGmtCreate()));
            orderDownloadResult.setCheckIn(DateUtils.toYYMMddStr(orderHead.getCheckIn()));
            orderDownloadResult.setCheckOut(DateUtils.toYYMMddStr(orderHead.getCheckOut()));
            orderDownloadResult.setPhone(orderHead.getContactPhone());
            orderDownloadResult.setName(orderHead.getContactName());
            orderDownloadResult.setStatus(OrderStatusEnum.getDesc(orderHead.getStatus()));
            orderDownloadResult.setArea(orderHead.getAddress());
            orderDownloadResult.setCouponValue(FormatUtils.fenToYuan(orderHead.getCouponValue()));
            orderDownloadResult.setSnapshotTotalFee(FormatUtils.fenToYuan(orderHead.getSnapshotTotalFee()));
            orderDownloadResult.setSnapshotRefundFee(orderHead.getSnapshotRefundFee() == null || orderHead.getSnapshotRefundFee() == 0 ? "0" : FormatUtils.fenToYuan(orderHead.getSnapshotRefundFee()));
            if ("yyks".equals(sourceType)) {
                setBankMessage(orderDownloadResult, orderHead);
            }
            //设置客房成交价和客房标准订房价
            if (null != orderHead.getDays() && 1 == orderHead.getDays()) {
                orderDownloadResult.setDealPrice(FormatUtils.fenToYuan(orderBillMap.get(orderHead.getOrderNo()).getDealPrice()));
                orderDownloadResult.setSalePrice(FormatUtils.fenToYuan(orderBillMap.get(orderHead.getOrderNo()).getSalePrice()));
            } else {
                setPrice(orderHead, orderDownloadResult);
            }
            orderDownloadResults.add(orderDownloadResult);
        }
        return orderDownloadResults;
    }

    /**
     * 写入酒店银行相关账号信息
     *
     * @param orderDownloadResult
     * @param orderHead
     */
    private void setBankMessage(OrderDownloadResult orderDownloadResult, OrderHeadDownLoadResult orderHead) {
        if (null == orderHead) {
            return;
        }
        String payAccounts = orderHead.getPayAccounts();
        try {
            JSONObject jsonObject = JSONObject.parseObject(payAccounts).getJSONObject("pay_accounts");
            PayAccountDTO payAccountDTO = jsonObject.toJavaObject(PayAccountDTO.class);
            orderDownloadResult.setBankCard(payAccountDTO.getBankCard());
            orderDownloadResult.setUserName(payAccountDTO.getUserName());
            if (payAccountDTO.getBankName() != null && payAccountDTO.getBranchBankName() != null) {
                orderDownloadResult.setBankNameAndBranch(payAccountDTO.getBankName() + "-" + payAccountDTO.getBranchBankName());
            }
            if (payAccountDTO.getBankName() != null && payAccountDTO.getBranchBankName() == null) {
                orderDownloadResult.setBankNameAndBranch(payAccountDTO.getBankName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Map<String, OrderBill> getOrderBillMap(List<OrderHeadDownLoadResult> orderHeads) {
        if (null == orderHeads || orderHeads.size() == 0) {
            return Maps.newHashMap();
        }
        List<String> orderNos = Lists.transform(orderHeads, OrderHeadDownLoadResult::getOrderNo);
        List<OrderBill> orderBills = orderBillService.selectByOrderNos(orderNos);
        Map<String, OrderBill> map = Maps.newHashMap();
        for (OrderBill orderBill : orderBills) {
            map.put(orderBill.getOrderNo(), orderBill);
        }
        return map;

    }

    /**
     * 设置客房成交价和客房标准订房价
     *
     * @param orderHead
     * @param orderDownloadResult
     */
    private void setPrice(OrderHeadDownLoadResult orderHead, OrderDownloadResult orderDownloadResult) {
        List<OrderBill> orderBills = orderBillService.list(new QueryWrapper<OrderBill>().eq(OrderBill.ORDER_NO, orderHead.getOrderNo()).orderByAsc(OrderBill.IN_DATE));
        if (orderBills == null || orderBills.size() == 0) {
            return;
        }
        //客房成交价
        orderDownloadResult.setDealPrice(FormatUtils.fenToYuan(orderBills.get(0).getDealPrice()));
//        //客房标准订房价
//        List<Date> dates = Lists.transform(orderBills, OrderBill::getInDate);
//        List<Integer> salePrices = null;
//        //C2B
//        if (orderHead.getVipFlag() == 0) {
//            List<RoomCalendarInfo> roomCalendarInfos = roomCalendarInfoService.list(new QueryWrapper<RoomCalendarInfo>().eq(RoomCalendarInfo.ID, orderHead.getRoomId()).in(RoomCalendarInfo.DATE, dates));
//            if (roomCalendarInfos != null && roomCalendarInfos.size() > 0) {
//                salePrices = Lists.transform(roomCalendarInfos, RoomCalendarInfo::getSalePrice);
//            }
//        } else {
//            List<RoomCalendarVipInfo> roomCalendarVipInfos = roomCalendarVipInfoService.list(new QueryWrapper<RoomCalendarVipInfo>().eq(RoomCalendarVipInfo.ID, orderHead.getRoomId()).in(RoomCalendarVipInfo.DATE, dates));
//            if (roomCalendarVipInfos != null && roomCalendarVipInfos.size() > 0) {
//                salePrices = Lists.transform(roomCalendarVipInfos, RoomCalendarVipInfo::getSalePrice);
//
//            }
//        }
        List<Integer> salePrices = Lists.transform(orderBills, OrderBill::getSalePrice);
        List<String> strSalePrices = Lists.newArrayList();
        for (Integer salePrice : salePrices) {
            strSalePrices.add(FormatUtils.fenToYuan(salePrice));
        }
        orderDownloadResult.setSalePrice(Joiners.COMMA.join(strSalePrices));
    }

    /**
     * 将订单对象转换成Map<Integer, HotelInfo>，key为酒店id，value为酒店
     *
     * @param orderHeads
     * @return
     */
    @Override
    public Map<Integer, HotelInfo> getHotelInfoMap(List<OrderHead> orderHeads) {
        if (orderHeads == null || orderHeads.size() == 0) {
            return Maps.newHashMap();
        }
        List<Integer> hotelIds = Lists.transform(orderHeads, OrderHead::getHotelId);
        List<HotelInfo> hotelInfos = hotelInfoService.selectByIds(hotelIds);
        return Maps.uniqueIndex(hotelInfos, HotelInfo::getId);
    }

    /**
     * 根据订单号修改订单状态
     *
     * @param orderNo
     * @param status
     * @return
     */
    @Override
    public Boolean updateStatusByOrderNo(String orderNo, Integer status) {
        if (Arguments.strIsNull(orderNo)) {
            throw new ServiceException("订单号不能为空");
        }
        if (status == null) {
            throw new ServiceException("修改的状态不能为空");
        }
        OrderHead orderHead = baseMapper.selectOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, orderNo));
        if (orderHead == null) {
            throw new ServiceException("该订单不存在");
        }
        orderHead.setStatus(status);
        if (baseMapper.updateById(orderHead) != 1) {
            throw new ServiceException("修改入住中失败");
        }
        return true;
    }

    /**
     * 订单详情
     *
     * @param orderNo
     * @return
     */
    @Override
    public OrderHeadDetail getOrderDetail(String orderNo) {
        try {
            OrderHead orderHead = baseMapper.selectOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, orderNo));
            if (orderHead == null) {
                throw new ServiceException("该订单不存在");
            }
            EsHotelInfo hotelInfo = null;
            EsRoomInfo roomInfo = null;
            OrderHeadDetail detail = ObjectConvertUtil.convertObject(orderHead, OrderHeadDetail.class);
            if (null == detail) {
                return new OrderHeadDetail();
            }
            detail.setPhone(orderHead.getContactPhone());
            detail.setName(orderHead.getContactName());
            detail.setCheckIn(DateUtils.toYYMMddStr(orderHead.getCheckIn()));
            detail.setCheckOut(DateUtils.toYYMMddStr(orderHead.getCheckOut()));
            detail.setStatus(OrderStatusEnum.getDesc(orderHead.getStatus()));
            detail.setCouponInfoPrice(getCouponPrice(orderHead));
            detail.setOrderTotalPrice(orderHead.getSnapshotTotalFee());
            if (orderHead.getPaymentMethod() != null) {
                detail.setPayMethod(PayTypeEnum.getDesc(orderHead.getPaymentMethod()));
            }
            List<OrderBill> orderBills = orderBillService.list(new QueryWrapper<OrderBill>().eq(OrderBill.ORDER_NO, orderHead.getOrderNo()));
            if (orderBills != null && orderBills.size() > 0) {
                detail.setOrderBillDetailList(orderBills.stream().map(e -> new OrderBillDetail(DateUtils.toYYMMddStr(e.getInDate()), e.getOriginPrice(),
                        e.getSalePrice(), e.getBottomPrice(), e.getDealPrice())).collect(Collectors.toList()));
                OrderBill orderBill = orderBills.get(0);
                if (orderBill != null && orderBill.getHotelExtraInfo() != null) {
                    hotelInfo = JSONUtil.toBean(orderBill.getHotelExtraInfo(), EsHotelInfo.class);
                }
                if (orderBill != null && orderBill.getRoomExtraInfo() != null) {
                    roomInfo = JSONUtil.toBean(orderBill.getRoomExtraInfo(), EsRoomInfo.class);
                }
            }
            if (hotelInfo != null) {
                detail.setHotelAddress(hotelInfo.getAddress());
                detail.setHotelName(hotelInfo.getName());
                detail.setHotelPhone(hotelInfo.getPhone());
                detail.setHotelTel(hotelInfo.getTel());
            }
            if (roomInfo != null) {
                detail.setRoomName(roomInfo.getTitle());
            }
            return detail;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new OrderHeadDetail();
    }

    /**
     * 发送拒绝短信
     *
     * @param orderHead
     * @param type
     * @param hotelInfo
     */
    private void refundSms(OrderHead orderHead, String type, HotelInfo hotelInfo) {
        try {
            RoomInfo roomInfo = roomInfoService.getById(orderHead.getRoomId());
            String daytime = DateUtils.toYYMMddStr(orderHead.getCheckIn());
            String phone = orderHead.getContactPhone();
            String hotelName = hotelInfo.getName();
            String roomType = roomInfo == null ? null : roomInfo.getTitle();
            String checkOut = DateUtils.toYYMMddStr(orderHead.getCheckOut());
            Integer count = DateUtils.getDayByBeginEnd(orderHead.getCheckIn(), orderHead.getCheckOut()).intValue();
            //酒店退款给用户发送短信
            if (type.equals(RefundTypeEnum.HOTEL.desc())) {
                smsService.sendSmsForHotelRefund(phone, daytime, hotelName, roomType);
                //将酒店发起退款申请记录写入表中
                Map<String, String> map = templateService.orderAfterHandleValue(MessageTemplate.ORDER_HOTEL_REFUND, hotelName, daytime, checkOut, count);
                noticeService.createNoticeAndSave(map, orderHead.getUserId(), hotelInfo.getId());
            }
        } catch (Exception e) {
            log.error("发送退款短信失败{}", e.getLocalizedMessage());
        }
    }

    /**
     * 有券的话，将券的状态修改为未使用，并增加房间个数
     *
     * @param orderHead
     */
    private Boolean updateCouponAndRoomCount(OrderHead orderHead) {
        try {
            //退款成功，如果使用券，将券的状态修改为未使用
            if (null != orderHead.getUserCouponId() && orderHead.getUserCouponId() != 0) {
                userCouponService.updateCouponUseById(orderHead.getUserCouponId(), null, false);
            }
            if (null != orderHead.getVipFlag()) {
                setRoomCount(orderHead.getOrderNo(), orderHead.getVipFlag(), 1);
            }
            return true;
        } catch (ServiceException e) {
            log.info(e.getMessage());
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public List<String> getHotelPics(HotelInfo hotelInfo) {
        try {
            HotelExtraInfo hotelExtraInfo = JSONObject.parseObject(hotelInfo.getExtraInfo(), HotelExtraInfo.class);
            return hotelExtraInfo.getImgUrlList();
        } catch (Exception e) {
            log.info("酒店图片解析异常hotelId = {}", hotelInfo.getId());
            e.printStackTrace();
        }
        return Lists.newArrayList();
    }


    //===================admin - app 实现相关的方法=====================

    @Override
    public CommonResult<CommonPage<AppOrderInfoDTO>> myAdminAppPageList(QueryOrderParam param, AccountInfo accountInfo) {

        CommonPage<AppOrderInfoDTO> orderInfoDTOCommonPage = new CommonPage<>();
        //将查询条件组装成map
        Map<String, Object> queryMap = this.getQueryMap(param, accountInfo);
        PageHelper.startPage(1, param.getPageSize());
        List<OrderHead> orderHeadList = baseMapper.selectPageByMap(queryMap);
        if (!CollectionUtils.isEmpty(orderHeadList)) {
            Map<String, OrderHead> maps = orderHeadList.stream().collect(Collectors.toMap(OrderHead::getOrderNo,
                    Function.identity(), (key1, key2) -> key2));
            CommonPage<OrderHead> orderHeadCommonPage = CommonPage.restPage(param.getPageNum(), param.getLastId(), orderHeadList);

            //得到酒店的列表信息
            List<Integer> roomIds = orderHeadList.stream().map(OrderHead::getRoomId).collect(Collectors.toList());
            List<RoomInfo> roomInfoList = roomInfoService.selectByIds(roomIds);
            Map<Integer, RoomInfo> roomInfoMap = roomInfoList.stream().collect(Collectors.toMap(RoomInfo::getId,
                    Function.identity(), (key1, key2) -> key2));

            orderInfoDTOCommonPage = MyBeanUtils.convertCommonPageList(orderHeadCommonPage, AppOrderInfoDTO.class);
            //组装相关关联数据信息
            if (!CollectionUtils.isEmpty(orderInfoDTOCommonPage.getList())) {
                orderInfoDTOCommonPage.getList().forEach(appOrderInfoDTO -> {
                    JsonPersonInfo personInfo = new JsonPersonInfo();
                    OrderHead orderHead = maps.get(appOrderInfoDTO.getOrderNo());
                    personInfo.setName(orderHead.getContactName());
                    personInfo.setPhone(orderHead.getContactPhone());
                    appOrderInfoDTO.setJsonPersonInfo(personInfo);
                    appOrderInfoDTO.setVitalPersonInfo(JSONObject.toJSONString(personInfo));

                    JsonOrderExtraInfo extraInfo = JSONObject.parseObject(appOrderInfoDTO.getExtraInfo(), JsonOrderExtraInfo.class);
                    if (null != extraInfo && !CollectionUtils.isEmpty(extraInfo.getRoomImgUrls())) {
                        appOrderInfoDTO.setRoomUrls(extraInfo.getRoomImgUrls());
                    } else {
                        //如果暂时没有这些图片，需要去房间中去查询
                        RoomInfo roomInfo = roomInfoMap.get(appOrderInfoDTO.getRoomId());
                        if (null != roomInfo && !StringUtils.isEmpty(roomInfo.getExtraInfo())) {
                            JsonImageRoom jsonImageRoom = JSONObject.parseObject(roomInfo.getExtraInfo(), JsonImageRoom.class);
                            if (null != jsonImageRoom && !CollectionUtils.isEmpty(jsonImageRoom.getImgUrlList())) {
                                appOrderInfoDTO.setRoomUrls(jsonImageRoom.getImgUrlList());
                            }
                        } else {
                            appOrderInfoDTO.setRoomUrls(Lists.newArrayList());
                        }
                    }
                });
            }
        }
        return CommonResult.success(orderInfoDTOCommonPage);
    }

    private Map<String, Object> getQueryMap(QueryOrderParam queryOrderParam, AccountInfo accountInfo) {
        Map<String, Object> paramMap = Maps.newHashMap();
        //状态结果集
        List<Integer> statusList = null;
        if (ArgumentsCheckUtil.notEmpty(queryOrderParam.getStatus())) {
            statusList = Splitters.splitToInteger(queryOrderParam.getStatus(), Splitters.COMMA);
        }
        paramMap.put("statusList", statusList);
        Date orderCreateDate = DateUtils.yyyyMMddToDate(queryOrderParam.getOrderDate());
        if (queryOrderParam.getOrderDate() != null) {
            paramMap.put("orderEndDate", DateUtils.afterDaysToDate(orderCreateDate, 1L));
        }
        paramMap.put("orderDate", orderCreateDate);
        if (queryOrderParam.getDateStart() != null) {
            paramMap.put("dateStart", DateUtils.toDateTime(queryOrderParam.getDateStart()));
        }
        if (queryOrderParam.getDateEnd() != null) {
            paramMap.put("dateEnd", DateUtils.toDateTime(queryOrderParam.getDateEnd()));
        }
        paramMap.put("checkIn", queryOrderParam.getCheckIn());
        paramMap.put("checkOut", queryOrderParam.getCheckOut());
        paramMap.put("type", accountInfo.getType());
        paramMap.put("id", accountInfo.getId());
        //订单C2B和B2C结果集
        List<Integer> vipList = Lists.newArrayList();
        if (queryOrderParam.getVipFlag() != null) {
            if (queryOrderParam.getVipFlag() == 0 || queryOrderParam.getVipFlag() == 2) {
                vipList.add(0);
                vipList.add(2);
            } else {
                vipList.add(queryOrderParam.getVipFlag());
            }
        }
        paramMap.put("vipList", vipList);
        paramMap.put("lastId", queryOrderParam.getLastId());
        //订单来源类型，如果为空，则显示全部;
        paramMap.put("sourceType", queryOrderParam.getSourceType());

        return paramMap;
    }

    @Override
    public CommonResult<AppOrderInfoDTO> getAdminAppOrderDetail(GetOrderDetailParam param, AccountInfo accountInfo) {

        OrderHeadDetail orderDetail = this.getOrderDetail(param.getOrderNo());

        AppOrderInfoDTO orderInfoDTO = MyBeanUtils.convert(orderDetail, AppOrderInfoDTO.class);
        convertOrderDTO(orderInfoDTO, orderDetail);
        //优惠券价格
        orderInfoDTO.setCouponPrice(orderDetail.getCouponInfoPrice());
        //原价
        orderInfoDTO.setPrice(orderDetail.getSnapshotOriginTotalFee());
        //现价
        orderInfoDTO.setSnapshotRoomPrice(orderDetail.getSnapshotOriginTotalFee());
        //成交价[用户出价]
        orderInfoDTO.setDealPrice(orderDetail.getOrderBillDetailList().get(0).getDealPrice());
        //实付价格
        orderInfoDTO.setSnapshotTotalFee(orderDetail.getOrderTotalPrice());
        return CommonResult.success(orderInfoDTO);
    }

    @Override
    public CommonResult checkIn(UpdateCheckInParam param, AccountInfo accountInfo) {

        //查询订单是否存在；
        OrderHead orderHead = baseMapper.selectOne(new QueryWrapper<OrderHead>().eq(OrderHead.ORDER_NO, param.getOrderNo()));
        if (null != orderHead && orderHead.getStatus().equals(OrderStatus.preCheckIn)) {
            long inRoom = orderHead.getCheckIn().getTime();
            if (inRoom > System.currentTimeMillis()) {
                return CommonResult.failed("不是当天，不能确认入住");
            }
            orderHead.setStatus(OrderStatus.living);
            boolean count = this.update(orderHead, new UpdateWrapper<OrderHead>().eq(OrderHead.ORDER_NO, param.getOrderNo()));
            if (count) {
                return CommonResult.success(null, "操作成功");
            }
        }

        return CommonResult.failed("操作失败");
    }

    @Override
    public CommonResult<List<AppIndexDTO>> statFeeByAdminAppIndex(QueryStatFeeParam param, AccountInfo accountInfo) {


        List<AppIndexDTO> appIndexDTOList = Lists.newArrayList();
        AppIndexDTO appIndexDTO = new AppIndexDTO();

        //根据登录账户获取该账户下的酒店
        List<Integer> hotelIds = hotelInfoService.getHotelInfoByAccountIdToId(accountInfo);
        Map<String, Object> queryMap = Maps.newHashMap();
        if (accountInfo.getType() != AccountType.Administrator) {
            queryMap.put("hotelIds", hotelIds);
        }
        queryMap.put("orderStart", new Date(param.getOrderStart()));
        queryMap.put("orderEnd", new Date(param.getOrderEnd()));
        String vipFlag = "0,2";
        queryMap.put("vipFlags", Splitters.splitToInteger(vipFlag, Splitters.COMMA));
        StatisticalResult statisticalResult = baseMapper.statFee(queryMap);

        appIndexDTO.setTotalFee((long) statisticalResult.getTotalFee());
        appIndexDTO.setTotalOrder(statisticalResult.getTotalOrder());
        appIndexDTO.setIndexDate(DateUtils.stampToYMDStr(param.getOrderStart()));
        appIndexDTO.setTotalRunningWater((long) statisticalResult.getSnapshotRoomPrice());
        appIndexDTO.setNewHotelCount(getAddHotelByTime(param, accountInfo));
        appIndexDTOList.add(appIndexDTO);

        return CommonResult.success(appIndexDTOList);
    }

    @Override
    public CommonResult<CommonPage<AppOrderInfoDTO>> getOrderNotice(GetOrderNoticeParam param, AccountInfo accountInfo) {

        CommonPage<AppOrderInfoDTO> orderInfoDTOCommonPage = new CommonPage<>();
        //查询订单状态为2,7的订单信息
        QueryOrderParam queryOrderParam = new QueryOrderParam();
        queryOrderParam.setStatus(param.getStatus());
        //通知里面只查询c2b的订单
        queryOrderParam.setVipFlag(0);
        //得到查询的Map信息
        Map<String, Object> queryMap = this.getQueryMap(queryOrderParam, accountInfo);
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<OrderHead> orderHeadList = baseMapper.selectPageByMap(queryMap);
        if (!CollectionUtils.isEmpty(orderHeadList)) {
            CommonPage<OrderHead> orderHeadCommonPage = CommonPage.restPage(param.getPageNum(), param.getLastId(), orderHeadList);
            orderInfoDTOCommonPage = MyBeanUtils.convertCommonPageList(orderHeadCommonPage, AppOrderInfoDTO.class);
            //调用拼接订单的字符串
            Map<String, OrderHead> orderHeadMap = orderHeadList.stream().collect(Collectors.toMap(OrderHead::getOrderNo, Function.identity(),
                    (key1, key2) -> key2));
            orderInfoDTOCommonPage.getList().forEach(appOrderInfoDTO -> {
                appOrderInfoDTO.setContextMessage(OrderHead.convertMessage(orderHeadMap.get(appOrderInfoDTO.getOrderNo())));
            });
        }
        return CommonResult.success(orderInfoDTOCommonPage);
    }

    @Override
    public CommonResult<List<AppIndexDTO>> getStatisticsData(QueryStatFeeParam queryStatFeeParam, AccountInfo accountInfo) {

        String dataType;
        if (queryStatFeeParam.getDataType() != null && !"".equals(queryStatFeeParam.getDataType())) {
            dataType = queryStatFeeParam.getDataType();
        } else {
            dataType = ONE_MONTH;
        }

        List<Integer> hotelIdList = null;
        if (!accountInfo.getType().equals(AccountType.Administrator)) {
            hotelIdList = hotelInfoService.getHotelInfoByAccountIdToId(accountInfo);
            //未查到所关联酒店
            if (hotelIdList == null || hotelIdList.size() < 1) {
                return CommonResult.success(Lists.newArrayList(), "你的数据为空");
            }
        }
        Map<String, Object> queryMap = Maps.newHashMap();
        queryMap.put("dataType", dataType);
        queryMap.put("hotelIds", hotelIdList);
        queryMap.put("orderStart", queryStatFeeParam.getOrderStart() == null ? null : new Date(queryStatFeeParam.getOrderStart()));
        queryMap.put("orderEnd", queryStatFeeParam.getOrderEnd() == null ? null : new Date(queryStatFeeParam.getOrderEnd()));

        List<AppIndexDTO> appIndexDTOList = baseMapper.selectDataStat(queryMap);

        if (!CollectionUtils.isEmpty(appIndexDTOList)) {
            appIndexDTOList.forEach(appIndexDTO -> {
                if (appIndexDTO.getTotalFee() == null) {
                    appIndexDTO.setTotalFee(0L);
                }
                if (appIndexDTO.getNewHotelCount() == null) {
                    appIndexDTO.setNewHotelCount(0);
                }
            });
        }
        return CommonResult.success(appIndexDTOList);
    }

    /**
     * 计算现价的 ————> 总价
     *
     * @param orderBillDetailList 天数数据
     * @return 返回总价结果
     */
    private Integer sumCurPriceTotal(List<OrderBillDetail> orderBillDetailList) {
        int total = 0;
        if (!CollectionUtils.isEmpty(orderBillDetailList)) {
            total = orderBillDetailList.stream().mapToInt(OrderBillDetail::getSalePrice).sum();
        }
        return total;
    }

    /**
     * 参数转换(兼容老版本)
     *
     * @param orderInfoDTO 订单DTO
     * @param orderDetail  订单详情
     */
    private void convertOrderDTO(AppOrderInfoDTO orderInfoDTO, OrderHeadDetail orderDetail) {

        if (null != orderDetail) {
            orderInfoDTO.setStatus(OrderStatusEnum.getValue(orderDetail.getStatus()));
            orderInfoDTO.setSnapshotHotelName(orderDetail.getHotelName());
            orderInfoDTO.setHotelPhone(orderDetail.getHotelTel());
            //其他信息
            Map<String, String> extraInfoMap = Maps.newHashMap();
            extraInfoMap.put("snapshot_hotel_address", orderDetail.getHotelAddress());
            extraInfoMap.put("snapshot_count", orderDetail.getRoomCount().toString());
            extraInfoMap.put("snapshot_tel_phone", orderDetail.getHotelTel());
            orderInfoDTO.setExtraInfo(JSONObject.toJSONString(extraInfoMap));
            orderInfoDTO.setCheckIn(DateUtils.yyyyMMddToDate(orderDetail.getCheckIn()));
            orderInfoDTO.setCheckOut(DateUtils.yyyyMMddToDate(orderDetail.getCheckOut()));
            orderInfoDTO.setSnapshotRoomName(orderDetail.getRoomName());
            JsonPersonInfo personInfo = new JsonPersonInfo();
            personInfo.setName(orderDetail.getName());
            personInfo.setPhone(orderDetail.getPhone());
            orderInfoDTO.setJsonPersonInfo(personInfo);
            orderInfoDTO.setVitalPersonInfo(JSONObject.toJSONString(personInfo));
            orderInfoDTO.setPaymentMethod(PayTypeEnum.getValue(orderDetail.getPayMethod()));
        }
    }

    /**
     * 得到某个时间段的新增酒店
     *
     * @return 返回新增酒店
     */
    private Integer getAddHotelByTime(QueryStatFeeParam queryStatFeeParam, AccountInfo accountInfo) {


        return hotelInfoService.getNewHotelCount(new Date(queryStatFeeParam.getOrderStart()),
                new Date(queryStatFeeParam.getOrderEnd()), accountInfo.getId(), accountInfo.getType());

    }

    /**
     * C2B房态增加回去
     *
     * @param orderNo 订单号
     * @param vipFlag 是否是甄选订单(0不是，1是)
     * @param type    0代表订单取消，1代表订单退款
     */
    @Override
    public Boolean setRoomCount(String orderNo, Integer vipFlag, Integer type) {
        OrderHead orderHead = getOne(
                new QueryWrapper<OrderHead>()
                        .eq(OrderHead.ORDER_NO, orderNo)
        );
        if (Objects.nonNull(orderHead) && (StrUtil.isBlank(orderHead.getSourceType()) || Objects.equals(orderHead.getSourceType(), HotelSourceType.YYKS))) {
            List<OrderBill> orderBills = orderBillService.list(new QueryWrapper<OrderBill>().eq(OrderBill.ORDER_NO, orderNo));
            if (null == orderBills || orderBills.size() <= 0) {
                log.info("订单详情不存在orderNo = {}", orderNo);
                return false;
            }
            for (OrderBill orderBill : orderBills) {
                try {
                    String roomJson = orderBill.getRoomCalendarInfo();
                    //C2B单和b2c订单 v3.4
                    if (Objects.equals(0, vipFlag) || Objects.equals(2, vipFlag)) {
                        RoomCalendarInfo roomCalendarInfo = JSONUtil.toBean(roomJson, RoomCalendarInfo.class);
                        if (null != roomCalendarInfo) {
                            RoomCalendarInfo c2b = roomCalendarInfoService.getById(roomCalendarInfo.getId());
                            if (c2b != null) {
                                if (0 == type && null != c2b.getLockCount() && c2b.getLockCount() > 0) {
                                    c2b.setCount(c2b.getCount() + orderBill.getRoomCount());
                                    c2b.setLockCount(c2b.getLockCount() - orderBill.getRoomCount() < 0 ? 0 : c2b.getLockCount() - orderBill.getRoomCount());
                                    if (!roomCalendarInfoService.updateById(c2b)) {
                                        log.info("更新c2b订单房态失败orderNo = {}", orderNo);
                                    }
                                }
                                if (1 == type) {
                                    c2b.setCount(c2b.getCount() + orderBill.getRoomCount());
                                    if (!roomCalendarInfoService.updateById(c2b)) {
                                        log.info("更新c2b订单房态失败orderNo = {}", orderNo);
                                    }
                                }
                            }
                        }
                        //发送房态更新消息
                        mqProducerService.sendEsUpdate(
                                new EsUpdateMessage()
                                        .setType(EsIndexConstant.JOIN_TYPE_ROOM)
                                        .setSourceType(HotelSourceType.YYKS)
                                        .setSourceIds(CollectionUtil.newArrayList(
                                                StrUtil.isNotBlank(orderHead.getSourceRoomId()) ? orderHead.getSourceRoomId() : String.valueOf(orderHead.getRoomId()))
                                        ), 5
                        );
                    }
                    //甄选单
                    if (Objects.equals(1, vipFlag)) {
                        RoomCalendarVipInfo roomCalendarVipInfo = JSONUtil.toBean(roomJson, RoomCalendarVipInfo.class);
                        if (null != roomCalendarVipInfo) {
                            RoomCalendarVipInfo vipInfo = roomCalendarVipInfoService.getById(roomCalendarVipInfo.getId());
                            if (vipInfo != null) {
                                if (0 == type && null != vipInfo.getLockCount() && vipInfo.getLockCount() > 0) {
                                    vipInfo.setCount(vipInfo.getCount() + orderBill.getRoomCount());
                                    vipInfo.setLockCount(vipInfo.getLockCount() - orderBill.getRoomCount() < 0 ? 0 : vipInfo.getLockCount() - orderBill.getRoomCount());
                                    if (!roomCalendarVipInfoService.updateById(vipInfo)) {
                                        log.info("更新vip订单房态失败orderNo = {}", orderNo);
                                    }
                                }
                                if (1 == type) {
                                    vipInfo.setCount(vipInfo.getCount() + orderBill.getRoomCount());
                                    if (!roomCalendarVipInfoService.updateById(vipInfo)) {
                                        log.info("更新vip订单房态失败orderNo = {}", orderNo);
                                    }
                                }
                            }
                        }
                    }
                    //jip
                    if (Objects.equals(3, vipFlag)) {
                        RoomCalendarJipInfo roomCalendarJipInfo = JSONUtil.toBean(roomJson, RoomCalendarJipInfo.class);
                        if (null != roomCalendarJipInfo) {
                            RoomCalendarJipInfo vipInfo = roomCalendarJipInfoService.getById(roomCalendarJipInfo.getId());
                            if (vipInfo != null) {
                                if (0 == type && null != vipInfo.getLockCount() && vipInfo.getLockCount() > 0) {
                                    vipInfo.setCount(vipInfo.getCount() + orderBill.getRoomCount());
                                    vipInfo.setLockCount(vipInfo.getLockCount() - orderBill.getRoomCount() < 0 ? 0 : vipInfo.getLockCount() - orderBill.getRoomCount());
                                    if (!roomCalendarJipInfoService.updateById(vipInfo)) {
                                        log.info("更新vip订单房态失败orderNo = {}", orderNo);
                                    }
                                }
                                if (1 == type) {
                                    vipInfo.setCount(vipInfo.getCount() + orderBill.getRoomCount());
                                    if (!roomCalendarJipInfoService.updateById(vipInfo)) {
                                        log.info("更新vip订单房态失败orderNo = {}", orderNo);
                                    }
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * 查询酒店上次提现到现在的已完成订单
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<OrderListResult> listHotel(WithdrawalHotelOrderParam param) {
        HotelInfo hotelInfo = hotelInfoService.searchHotelByOperator(param.getAccountId());
        Arguments.beanIsNull(hotelInfo, "该酒店不存在");
        QueryWrapper<OrderHead> wrapper = new QueryWrapper<>();
        wrapper.eq(OrderHead.HOTEL_ID, hotelInfo.getId());
        wrapper.eq(OrderHead.SOURCE_TYPE, param.getSourceType());
        wrapper.eq(OrderHead.STATUS, OrderStatusEnum.POSTCHECKOUT.value());
        if (null == param.getStartTime()) {
            wrapper.between(OrderHead.GMT_CREATE, configService.getHotelDate(), new Date(param.getEndTime()));
        } else {
            wrapper.between(OrderHead.GMT_CREATE, new Date(param.getStartTime()), new Date(param.getEndTime()));
        }
        if (null != param.getVipFlag()) {
            wrapper.eq(OrderHead.VIP_FLAG, param.getVipFlag());
        }
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<OrderHead> orderHeads = baseMapper.selectList(wrapper);
        Map<Integer, UserInfo> userInfoMap = getUserInfoMap(orderHeads);
        PageInfo<OrderHead> pageInfo = PageInfo.of(orderHeads);
        List<OrderListResult> orderListResults = getOrderListResult(orderHeads, userInfoMap, null, null);
        return new PageResult<>(pageInfo.getTotal(), pageInfo.getPages(), pageInfo.isHasNextPage(), pageInfo.getNextPage(), orderListResults);
    }

    /**
     * 查询酒店上次提现到现在的已完成vip订单
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<OrderListResult> periodListHotel(WithdrawalPeriodOrderParam param) {
        Map<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("accountId", param.getAccountId());
        //酒店
        if (5 == param.getType()) {
            paramMap.put("types", Lists.newArrayList(1, 5));
        }
        //运营商
        if (20 == param.getType()) {
            paramMap.put("types", Lists.newArrayList(2, 6));
        }
        //卡商
        if (22 == param.getType()) {
            paramMap.put("types", Lists.newArrayList(9));
        }
        paramMap.put("sourceType", param.getSourceType());
        paramMap.put("vipFlag", param.getVipFlag());
        if (null == param.getStartTime()) {
            paramMap.put("startTime", configService.getHotelDate());
            paramMap.put("endTime", new Date(param.getEndTime()));
        } else {
            paramMap.put("startTime", new Date(param.getStartTime()));
            paramMap.put("endTime", new Date(param.getEndTime()));
        }
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<OrderHead> orderHeads = baseMapper.selectPeriodListHotel(paramMap);
        Map<Integer, UserInfo> userInfoMap = getUserInfoMap(orderHeads);
        PageInfo<OrderHead> pageInfo = PageInfo.of(orderHeads);
        List<OrderListResult> orderListResults = getOrderListResult(orderHeads, userInfoMap, null, null);
        return new PageResult<>(pageInfo.getTotal(), pageInfo.getPages(), pageInfo.isHasNextPage(), pageInfo.getNextPage(), orderListResults);
    }

    /**
     * 财务对账单列表
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<HotelStatementResult> listStatement(HotelStatementParam param) {
        Map<String, Object> map = Maps.newHashMap();
        if ((null != param.getStartTime() && null == param.getEndTime())
                || (null != param.getEndTime() && null == param.getStartTime())) {
            throw new ServiceException("对账日期必须填写完整");
        }
        if (null == param.getStartTime() && null == param.getEndTime()) {
            param.setStartTime(DateUtils.afterHoursToDate(DateUtils.dayBegin(0), 12L).getTime());
            param.setEndTime(DateUtils.afterHoursToDate(DateUtils.dayBegin(0), 12L).getTime());
        }
        map.put("startTime", new Date(param.getStartTime()));
        map.put("endTime", new Date(param.getEndTime()));
        map.put("hotelName", param.getHotelName());
        map.put("phone", param.getPhone());
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<HotelStatementResultDTO> hotelStatementResultDTOS = baseMapper.listStatement(map);
        PageInfo<HotelStatementResultDTO> pageInfo = PageInfo.of(hotelStatementResultDTOS);
        List<HotelStatementResult> results = getHotelStatementResult(hotelStatementResultDTOS);
        return new PageResult<>(pageInfo.getTotal(), pageInfo.getPages(), pageInfo.isHasNextPage(), pageInfo.getNextPage(), results);
    }

    /**
     * 财务对账单导出
     *
     * @param param
     * @return
     */
    @Override
    public List<HotelStatementResult> statementDownload(HotelStatementDownloadParam param) {
        Map<String, Object> map = Maps.newHashMap();
        if (null == param.getStartTime() && null == param.getEndTime()) {
            map.put("startTime", DateUtils.afterHoursToDate(DateUtils.dayBegin(0), 12L));
            map.put("endTime", DateUtils.afterHoursToDate(DateUtils.dayBegin(0), 12L));
        }
        List<HotelStatementResultDTO> hotelStatementResultDTOS = baseMapper.listStatement(map);
        return getHotelStatementResult(hotelStatementResultDTOS);
    }

    /**
     * 酒店财务对账单统计
     *
     * @param param
     * @return
     */
    @Override
    public List<StatisticalHotelResults> hotelStatementStat(AccountInfo loginUser, HotelStatementStatParam param) {
        HotelInfo hotelInfo = hotelInfoService.getHotelInfoAccountHotelInfo(loginUser);
        Map<String, Object> map = Maps.newHashMap();
        map.put("orderStart", new Date(param.getStartTime()));
        map.put("orderEnd", new Date(param.getEndTime()));
        map.put("hotelId", hotelInfo.getId());
        map.put("type", param.getType());
        List<StatisticalHotelResult> statisticalHotelResults = baseMapper.statHotelMonthAndDay(map);
        return ObjectConvertUtil.convertList(statisticalHotelResults, StatisticalHotelResults.class);
    }

    /**
     * 酒店财务对账单统计导出
     *
     * @param loginUser
     * @param param
     * @return
     */
    @Override
    public List<StatisticalHotelDownLoadResult> hotelStatementStatDownload(AccountInfo loginUser, HotelStatementStatDownLoadParam param) {
        HotelInfo hotelInfo = hotelInfoService.getHotelInfoAccountHotelInfo(loginUser);
        Map<String, Object> map = Maps.newHashMap();
        map.put("orderStart", new Date(param.getStartTime()));
        map.put("orderEnd", new Date(param.getEndTime()));
        map.put("hotelId", hotelInfo.getId());
        map.put("type", 1);
        List<StatisticalHotelResult> statisticalHotelResults = baseMapper.statHotelMonthAndDay(map);
        return getResult(statisticalHotelResults);
    }

    @Override
    public CommonResult<CommonPage<AppHotelBillDTO>> queryHotelBill(QueryHotelBillParam param) {

        CommonPage<AppHotelBillDTO> commonPage = new CommonPage<>();

        PageResult<HotelStatementResult> pageResult = this.listStatement(MyBeanUtils.convert(param, HotelStatementParam.class));
        if (null != pageResult && !CollectionUtils.isEmpty(pageResult.getList())) {
            Map<String, HotelStatementResult> resultMap = pageResult.getList().stream()
                    .collect(Collectors.toMap(HotelStatementResult::getHotelName,
                            Function.identity(), (key1, key2) -> key2));
            List<AppHotelBillDTO> hotelBillDTOList = MyBeanUtils.convertArrayList(pageResult.getList(), AppHotelBillDTO.class);
            //返回的相关酒店营业额的判断
            hotelBillDTOList.forEach(appHotelBillDTO -> {
                HotelStatementResult statementResult = resultMap.get(appHotelBillDTO.getHotelName());
                if (null != statementResult && !StringUtils.isEmpty(statementResult.getTotalAmount())) {
                    appHotelBillDTO.setTotalAmount(Long.valueOf(
                            FormatUtils.yuanToFen(statementResult.getTotalAmount())
                    ));
                } else {
                    appHotelBillDTO.setTotalAmount(0L);
                }
            });
            commonPage.setList(hotelBillDTOList);
            commonPage.setPageNum(param.getPageNum());
            commonPage.setPageSize(param.getPageSize());
            commonPage.setTotal(pageResult.getTotal());
            commonPage.setTotalPage(Long.valueOf(pageResult.getPageCount()));
        }
        return CommonResult.success(commonPage);
    }

    @Override
    public CommonResult<List<AppIndexDTO>> queryBillByHotelId(QueryStatFeeParam param, AccountInfo accountInfo) {

        String dataType;
        if (param.getDataType() != null && !"".equals(param.getDataType())) {
            dataType = param.getDataType();
        } else {
            dataType = ONE_MONTH;
        }
        HotelInfo hotelInfo = hotelInfoService.getHotelInfoAccountHotelInfo(accountInfo);
        Map<String, Object> queryMap = Maps.newHashMap();
        queryMap.put("dataType", dataType);
        queryMap.put("hotelId", hotelInfo.getId());
        queryMap.put("orderStart", param.getOrderStart() == null ? null : new Date(param.getOrderStart()));
        queryMap.put("orderEnd", param.getOrderEnd() == null ? null : new Date(param.getOrderEnd()));

        List<AppIndexDTO> appIndexDTOList = baseMapper.selectHotelDataStat(queryMap);
        if (!CollectionUtils.isEmpty(appIndexDTOList)) {
            appIndexDTOList.forEach(appIndexDTO -> {
                if (appIndexDTO.getTotalFee() == null) {
                    appIndexDTO.setTotalFee(0L);
                }
                if (appIndexDTO.getNewHotelCount() == null) {
                    appIndexDTO.setNewHotelCount(0);
                }
            });
        }
        return CommonResult.success(appIndexDTOList);
    }

    private List<StatisticalHotelDownLoadResult> getResult(List<StatisticalHotelResult> statisticalHotelResults) {

        if (null == statisticalHotelResults || 0 == statisticalHotelResults.size()) {
            return Lists.newArrayList();
        }
        List<StatisticalHotelDownLoadResult> results = Lists.newArrayList();
        statisticalHotelResults.forEach(e -> {
            StatisticalHotelDownLoadResult result = ObjectConvertUtil.convertObject(e, StatisticalHotelDownLoadResult.class);
            if (null != result) {
                result.setTotalAmount(FormatUtils.fenToYuan(e.getTotalAmount()));
            }
            results.add(result);
        });
        return results;
    }

//    /**
//     * 补齐缺失的月
//     *
//     * @param type
//     * @param statisticalHotelResults
//     * @return
//     */
//    private List<StatisticalHotelResults> disPoseResult(Integer type, List<StatisticalHotelResult> statisticalHotelResults) {
//        if (null == statisticalHotelResults || 0 == statisticalHotelResults.size()) {
//            return Lists.newArrayList();
//        }
//        List<String> lists = Lists.newArrayList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12");
//        List<String> dates = Lists.transform(statisticalHotelResults, StatisticalHotelResult::getStrDate);
//        if (1 == type) {
//            lists = DateListUtil.getMonthAllDays(statisticalHotelResults.get(0).getStrDate().substring(0, 7));
//            if (null != lists) {
//                lists.forEach(e -> {
//                    if (!dates.contains(e)) {
//                        String days = e.substring(e.length() - 2);
//                        if ("0".equals(days.substring(0, 1))) {
//                            days = days.replaceAll("0", "");
//                        }
//                        StatisticalHotelResult result = new StatisticalHotelResult();
//                        result.setDay(Integer.valueOf(days));
//                        result.setTotalAmount(0);
//                        result.setTotalOrder(0);
//                        statisticalHotelResults.add(result);
//                    }
//                });
//            }
//        }
//        if (2 == type) {
//            lists.forEach(e -> {
//                if (!dates.contains(e)) {
//                    StatisticalHotelResult result = new StatisticalHotelResult();
//                    result.setMonth(Integer.valueOf(e));
//                    result.setTotalAmount(0);
//                    result.setTotalOrder(0);
//                    statisticalHotelResults.add(result);
//                }
//            });
//        }
//        return ObjectConvertUtil.convertList(statisticalHotelResults, StatisticalHotelResults.class);
//    }

    private List<HotelStatementResult> getHotelStatementResult(List<HotelStatementResultDTO> hotelStatementResultDTOS) {
        if (null == hotelStatementResultDTOS || 0 == hotelStatementResultDTOS.size()) {
            return Lists.newArrayList();
        }
        List<HotelStatementResult> results = Lists.newArrayList();
        for (HotelStatementResultDTO resultDTO : hotelStatementResultDTOS) {
            HotelStatementResult result = ObjectConvertUtil.convertObject(resultDTO, HotelStatementResult.class);
            if (null == result) {
                continue;
            }
            if (Arguments.strNotNull(resultDTO.getPayAccounts()) && !"0".equals(resultDTO.getPayAccounts())) {
                try {
                    String payAccounts = resultDTO.getPayAccounts();
                    JSONObject jsonObject = JSONObject.parseObject(payAccounts).getJSONObject("pay_accounts");
                    PayAccountDTO payAccountDTO = jsonObject.toJavaObject(PayAccountDTO.class);
                    result.setBankCard(payAccountDTO.getBankCard());
                    result.setBankName(payAccountDTO.getBankName());
                    result.setBranchBankName(payAccountDTO.getBranchBankName());
                    result.setUserName(payAccountDTO.getUserName());
                    result.setTotalAmount(FormatUtils.fenToYuan(resultDTO.getTotalAmount()));
                } catch (Exception e) {
                    log.info("解析银行卡信息异常payAccounts = {}", resultDTO);
                    e.printStackTrace();
                }
            }
            results.add(result);
        }
        return results;
    }


    /*
    calendarModifyType 1,下单,2,取消,3,成功,4,成功取消
     */
    @Override
    public void updateRoomCalendarInfo(String orderNo, int calendarModifyType) {
        OrderHead orderHead = getOne(
                new QueryWrapper<OrderHead>()
                        .eq(OrderHead.ORDER_NO, orderNo)
                        .last("limit 1")
        );
        List<RoomCalendarInfo> roomCalendarInfos = roomCalendarInfoService.list(new QueryWrapper<RoomCalendarInfo>()
                .eq(RoomCalendarInfo.ROOM_ID, orderHead.getSourceRoomId())
                .ge(RoomCalendarVipInfo.DATE, orderHead.getCheckIn())
                .lt(RoomCalendarVipInfo.DATE, orderHead.getCheckOut()));
        ArrayList<RoomCalendarInfo> roomCalendarInfoArrayList = new ArrayList<>();
        for (RoomCalendarInfo roomCalendarInfo : roomCalendarInfos) {
            RoomCalendarInfo roomCalendarInfoNew = new RoomCalendarInfo();
            roomCalendarInfoNew.setId(roomCalendarInfo.getId());
            switch (calendarModifyType) {
                case 1:
                    if (roomCalendarInfo.getCount() < orderHead.getRoomCount()) {
                        throw new ServiceException("房间数量不足");
                    }
                    roomCalendarInfoNew.setCount(roomCalendarInfo.getCount() - orderHead.getRoomCount());
                    roomCalendarInfoNew.setLockCount(roomCalendarInfo.getLockCount() + orderHead.getRoomCount());
                    break;
                case 2:
                    if (roomCalendarInfo.getLockCount() < orderHead.getRoomCount()) {
                        throw new ServiceException("房态锁定房间不足");
                    }
                    roomCalendarInfoNew.setCount(roomCalendarInfo.getCount() + orderHead.getRoomCount());
                    roomCalendarInfoNew.setLockCount(roomCalendarInfo.getLockCount() - orderHead.getRoomCount());
                    break;
                case 3:
                    if (roomCalendarInfo.getLockCount() < orderHead.getRoomCount()) {
                        throw new ServiceException("房态锁定房间不足");
                    }
                    roomCalendarInfoNew.setLockCount(roomCalendarInfo.getLockCount() - orderHead.getRoomCount());
                    break;
                case 4:
                    roomCalendarInfoNew.setCount(roomCalendarInfo.getCount() + orderHead.getRoomCount());
                    break;
                default:
                    throw new ServiceException("房态修改类型不对");
            }
            roomCalendarInfoArrayList.add(roomCalendarInfoNew);
        }
        roomCalendarInfoService.updateBatchById(roomCalendarInfoArrayList);
        //发送房态更新消息
        mqProducerService.sendEsUpdate(
                new EsUpdateMessage()
                        .setType(EsIndexConstant.JOIN_TYPE_ROOM)
                        .setSourceType(HotelSourceType.YYKS)
                        .setSourceIds(CollectionUtil.newArrayList(orderHead.getSourceRoomId())), 5
        );
    }

    /**
     * 获取订单【状态】列表接口
     *
     * @param convert 操作人
     * @return
     */
    @Override
    public CommonResult<List<AppOrderStatusDTO>> getOrderStatusList(AccountInfo convert) {

        List<AppOrderStatusDTO> appOrderStatusDTOList = Lists.newArrayList();

        List<OrderStatusEnum> h = Arrays.asList(OrderStatusEnum.values());

        h.forEach(orderStatusEnum -> {
            AppOrderStatusDTO orderStatusDTO = new AppOrderStatusDTO();
            orderStatusDTO.setType(String.valueOf(orderStatusEnum.getValue()));
            orderStatusDTO.setValue(orderStatusEnum.getDesc());
            appOrderStatusDTOList.add(orderStatusDTO);
        });

        return CommonResult.success(appOrderStatusDTOList);
    }

    /**
     * 查询该用户是否是注册n天下的第一单
     *
     * @param day 大于等于0的数，0代表是否是注册当天下的单
     * @return
     */
    @Override
    public Boolean userOrderIsRegistTime(OrderHead orderHead, Integer day) {
        if (null == day || day < 0) {
            log.info("查询该用户是否是注册n天下的单 --> 参数day有误");
            return false;
        }
        if (Objects.isNull(orderHead)) {
            log.info("查询该用户是否是注册n天下的单 --> 订单为空");
            return false;
        }
        if (Objects.isNull(orderHead.getGmtCreate())) {
            log.info("查询该用户是否是注册n天下的单 --> 订单创建时间为空");
            return false;
        }
        UserInfo userInfo = userInfoService.getById(orderHead.getUserId());
        if (null == userInfo) {
            log.info("查询该用户是否是注册n天下的单 --> 该用户不存在orderHead = {}", orderHead);
            return false;
        }
        //获取用户注册n天后的时间
        Date sevenAfterDay = DateUtil.offsetDay(userInfo.getGmtCreate(), day).toJdkDate();
        if (DateUtil.compare(orderHead.getGmtCreate(), sevenAfterDay) > 0) {
            log.info("非注册{}天内下的单", day);
            return false;
        }
        return selectOrderByUserId(orderHead);
    }

    @Override
    public Boolean isFirstUserOrder(OrderHead orderHead) {
        List<Integer> statusList = new ArrayList<>();
        statusList.add(OrderStatus.living);
        statusList.add(OrderStatus.postCheckOut);
        QueryWrapper<OrderHead> queryWrapper = new QueryWrapper<>();
        queryWrapper.lt(OrderHead.GMT_CREATE, orderHead.getGmtCreate());
        queryWrapper.in(OrderHead.STATUS, statusList);
        queryWrapper.eq(OrderHead.USER_ID, orderHead.getUserId());
        Integer count = baseMapper.selectCount(queryWrapper);
        return count <= 0;
    }

    /**
     * 用户最近消费时间
     *
     * @param userId
     * @param vipFlag 订单类型逗号隔开，0 c2b，1vip，2b2c，3精选
     * @return
     */
    @Override
    public Date lastOrderTime(Integer userId, Integer vipFlag) {
        OrderHead orderHead = baseMapper.selectOne(new QueryWrapper<OrderHead>()
                .eq(OrderHead.USER_ID, userId)
                .eq(OrderHead.VIP_FLAG, vipFlag)
                .orderByDesc(OrderHead.GMT_CREATE)
                .last("limit 1"));
        return null == orderHead ? null : orderHead.getGmtCreate();
    }

    /**
     * 用户累计消费金额和累计单数(订单完成)
     *
     * @param userId
     * @param vipFlag 订单类型逗号隔开，0 c2b，1vip，2b2c，3精选
     * @return
     */
    @Override
    public UserOrderResult selectUserTotalAmount(Integer userId, Integer vipFlag) {
        return baseMapper.selectUserTotalAmount(userId, vipFlag);
    }

    /**
     * 数据大屏之全国销售额
     *
     * @param param
     * @return
     */
    @Override
    public DataScreenOrderResult statOrder(DataScreenOrderParam param) {
        DataScreenOrderResult orderResult = new DataScreenOrderResult();
        //查询年数据
        StatisticalResult yearResult = statFee(param.getYearOrderStart(), param.getYearOrderEnd(), param.getVipFlag());
        orderResult.setYearData(yearResult.getTotalFee());
        orderResult.setOrigYearData(yearResult.getSnapshotRoomPrice());
        //查询月数据
        StatisticalResult monthResult = statFee(param.getMonthOrderStart(), param.getMonthOrderEnd(), param.getVipFlag());
        orderResult.setMonthData(monthResult.getTotalFee());
        orderResult.setOrigMonthData(monthResult.getSnapshotRoomPrice());
        //查询日数据
        StatisticalResult dayResult = statFee(param.getDayOrderStart(), param.getDayOrderEnd(), param.getVipFlag());
        orderResult.setTodayData(dayResult.getTotalFee());
        orderResult.setOrigTodayData(dayResult.getSnapshotRoomPrice());
        return orderResult;
    }

    /**
     * 数据大屏之全国城市业绩
     *
     * @return
     */
    @Override
    public List<DataScreenCityOrderResult> statCityOrder() {
        return baseMapper.statCityOrder();
    }

    /**
     * 同步订单中的provinceName字段
     *
     * @return
     */
    @Override
    public Boolean syncProvinceName() {
        //同步省名称
        List<DataScreenSyncNameResult> provinceResults = baseMapper.syncProvinceName();
        for (DataScreenSyncNameResult provinceResult : provinceResults) {
            try {
                //将orderHead中的provinceName补全
                baseMapper.updateProvinceName(provinceResult.getProvinceName(), provinceResult.getProvinceAgentId());
            } catch (Exception e) {
                e.printStackTrace();
                log.info("更新provinceName字段失败provinceResult = {}", provinceResult);
            }
        }
        //同步市名称
        List<DataScreenSyncNameResult> cityResults = baseMapper.syncCityName();
        for (DataScreenSyncNameResult cityResult : cityResults) {
            try {
                //将orderHead中的provinceName补全
                if (StrUtil.isNotBlank(cityResult.getCityName())) {
                    List<String> lists = Splitters.splitToString(cityResult.getCityName(), Splitters.DOT);
                    baseMapper.updateCityName(lists.get(1), cityResult.getCityAgentId());
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.info("更新CityName字段失败cityResult = {}", cityResult);
            }
        }

        return true;
    }

    /**
     * 数据大屏之月销售额
     *
     * @param vipFlag 订单类型逗号隔开，0 c2b，1vip，2b2c，3精选
     * @return
     */
    @Override
    public List<DataScreenOrderMonthResult> statMonthOrder(String vipFlag) {
        Map<String, Object> map = Maps.newHashMap();
        Date nowDate = new Date();
        //获取当月开始时间
        DateTime beginOfMonth = DateUtil.beginOfMonth(nowDate);
        //获取当月的结束时间
        DateTime endOfMonth = DateUtil.endOfMonth(nowDate);
        DateTime sevenBeginOfMonth = DateUtil.offsetMonth(beginOfMonth, -11);
        //月统计
        map.put("type", 1);
        map.put("orderStart", sevenBeginOfMonth);
        map.put("orderEnd", endOfMonth);
        map.put("vipFlags", Splitters.splitToInteger(vipFlag, Splitters.COMMA));
        List<StatisticalResult> statisticalResults = baseMapper.statMonthAndDay(map);
        return ObjectConvertUtil.convertList(statisticalResults, DataScreenOrderMonthResult.class);
    }

    /**
     * 查询付费用户
     *
     * @return
     */
    @Override
    public int orderPayUserCount() {
        return baseMapper.selectOrderPayUserCount();
    }

    @Override
    public void updateInvoiceIsNull(String orderNo) {
        baseMapper.updateInvoiceIsNull(orderNo);
    }

    private Boolean selectOrderByUserId(OrderHead orderHead) {
        Integer count = baseMapper.selectCount(new QueryWrapper<OrderHead>()
                .eq(OrderHead.USER_ID, orderHead.getUserId())
                .lt(OrderHead.GMT_CREATE, orderHead.getGmtCreate())
                .in(OrderHead.STATUS, OrderStatus.living, OrderStatus.postCheckOut));
        return count <= 0;
    }

    private List<Integer> getHotelIdsByAccountId(Integer accountId, Integer type) {
        switch (type) {
            case 10://大V运营商
                //通过账户id和类型查询该账户下的酒店id集合
                List<Integer> hotelIds = hotelDeveloperRelationService.selectHotelIdsByAccountIdAndType(accountId, 1, 1);
                //如果是运营商，还需要查询运营商下的服务商下的酒店id集合
                List<Integer> accountIds = accountVipSalerRelationService.selectAccountIdsByParentId(accountId, 1);
                for (Integer id : accountIds) {
                    hotelIds.addAll(hotelDeveloperRelationService.selectHotelIdsByAccountIdAndType(id, 2, 1));
                }
                Set<Integer> sets = new HashSet<>(hotelIds);
                return Lists.newArrayList(sets);
            case 11://大V服务商
                return hotelDeveloperRelationService.selectHotelIdsByAccountIdAndType(accountId, 2, 1);
            case 12://大V卡商
                List<MemberCard> memberCards = memberCardService.selectBySalerIdAndSalerType(accountId, null, 1);
                return Lists.transform(memberCards, MemberCard::getHotelId);
            case 20://小V运营商
                List<Integer> miniHotelIds = hotelDeveloperRelationService.selectHotelIdsByAccountIdAndType(accountId, 1, 2);
                List<Integer> miniAccountIds = accountVipSalerRelationService.selectAccountIdsByParentId(accountId, 2);
                for (Integer id : miniAccountIds) {
                    miniHotelIds.addAll(hotelDeveloperRelationService.selectHotelIdsByAccountIdAndType(id, 2, 1));
                }
                Set<Integer> miniSets = new HashSet<>(miniHotelIds);
                return Lists.newArrayList(miniSets);
            case 21://小V服务商
                return hotelDeveloperRelationService.selectHotelIdsByAccountIdAndType(accountId, 2, 2);
            case 22://小V卡商
                List<MemberCard> miniMemberCards = memberCardService.selectBySalerIdAndSalerType(accountId, null, 2);
                return Lists.transform(miniMemberCards, MemberCard::getHotelId);
            default:
                return Lists.newArrayList();

        }
    }
}
